backpack-viewer 0.7.14 → 0.7.15
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/app/assets/index-Cab62Pxr.css +1 -0
- package/dist/app/assets/index-DpElI3pz.js +6 -0
- package/dist/app/index.html +2 -2
- package/dist/extensions/share/src/index.js +143 -138
- package/dist/server-api-routes.js +19 -0
- package/dist/sidebar.js +18 -2
- package/dist/style.css +16 -0
- package/package.json +1 -1
- package/dist/app/assets/index-BbX2AsyK.css +0 -1
- package/dist/app/assets/index-CSbPTbYZ.js +0 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{margin:0;padding:0;box-sizing:border-box}:root{--bg: #141414;--bg-surface: #1a1a1a;--bg-hover: #222222;--bg-active: #2a2a2a;--bg-elevated: #1e1e1e;--bg-inset: #111111;--border: #2a2a2a;--text: #d4d4d4;--text-strong: #e5e5e5;--text-muted: #737373;--text-dim: #525252;--accent: #d4a27f;--accent-hover: #e8b898;--badge-text: #141414;--glass-bg: rgba(20, 20, 20, .85);--glass-border: rgba(255, 255, 255, .08);--chip-bg: rgba(42, 42, 42, .7);--chip-bg-active: rgba(42, 42, 42, .9);--chip-bg-hover: rgba(50, 50, 50, .9);--chip-border-active: rgba(255, 255, 255, .06);--shadow: rgba(0, 0, 0, .6);--shadow-strong: rgba(0, 0, 0, .5);--z-canvas-overlay: 20;--z-panel: 30;--z-floating: 40;--z-panel-fullscreen: 45;--z-floating-primary: 50;--z-popup: 55;--z-modal: 60;--z-toast: 70;--canvas-edge: rgba(255, 255, 255, .08);--canvas-edge-highlight: rgba(212, 162, 127, .5);--canvas-edge-dim: rgba(255, 255, 255, .03);--canvas-edge-label: rgba(255, 255, 255, .2);--canvas-edge-label-highlight: rgba(212, 162, 127, .7);--canvas-edge-label-dim: rgba(255, 255, 255, .05);--canvas-arrow: rgba(255, 255, 255, .12);--canvas-arrow-highlight: rgba(212, 162, 127, .5);--canvas-node-label: #a3a3a3;--canvas-node-label-dim: rgba(212, 212, 212, .2);--canvas-type-badge: rgba(115, 115, 115, .5);--canvas-type-badge-dim: rgba(115, 115, 115, .15);--canvas-selection-border: #d4d4d4;--canvas-node-border: rgba(255, 255, 255, .15);--canvas-walk-edge: #e8d5c4}[data-theme=light]{--bg: #f5f5f4;--bg-surface: #fafaf9;--bg-hover: #f0efee;--bg-active: #e7e5e4;--bg-elevated: #f0efee;--bg-inset: #e7e5e4;--border: #d6d3d1;--text: #292524;--text-strong: #1c1917;--text-muted: #78716c;--text-dim: #a8a29e;--accent: #c17856;--accent-hover: #b07a5e;--badge-text: #fafaf9;--glass-bg: rgba(250, 250, 249, .85);--glass-border: rgba(0, 0, 0, .08);--chip-bg: rgba(214, 211, 209, .5);--chip-bg-active: rgba(214, 211, 209, .8);--chip-bg-hover: rgba(200, 197, 195, .8);--chip-border-active: rgba(0, 0, 0, .08);--shadow: rgba(0, 0, 0, .1);--shadow-strong: rgba(0, 0, 0, .15);--canvas-edge: rgba(0, 0, 0, .1);--canvas-edge-highlight: rgba(193, 120, 86, .6);--canvas-edge-dim: rgba(0, 0, 0, .03);--canvas-edge-label: rgba(0, 0, 0, .25);--canvas-edge-label-highlight: rgba(193, 120, 86, .8);--canvas-edge-label-dim: rgba(0, 0, 0, .06);--canvas-arrow: rgba(0, 0, 0, .15);--canvas-arrow-highlight: rgba(193, 120, 86, .6);--canvas-node-label: #57534e;--canvas-node-label-dim: rgba(87, 83, 78, .2);--canvas-type-badge: rgba(87, 83, 78, .5);--canvas-type-badge-dim: rgba(87, 83, 78, .15);--canvas-selection-border: #292524;--canvas-node-border: rgba(0, 0, 0, .1);--canvas-walk-edge: #1a1a1a}body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);overflow:hidden}#app{display:flex;height:100vh;width:100vw}#sidebar{width:280px;min-width:280px;background:var(--bg-surface);border-right:1px solid var(--border);border-left:3px solid var(--backpack-color, transparent);display:flex;flex-direction:column;padding:16px;overflow-y:auto}#sidebar.sidebar-collapsed{width:0;min-width:0;padding:0;overflow:hidden;border-right:none}.sidebar-heading-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.sidebar-heading-row h2{margin-bottom:0}.sidebar-collapse-btn{background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer;padding:4px 6px;line-height:1;transition:color .15s,border-color .15s}.sidebar-collapse-btn:hover{color:var(--text);border-color:var(--text-muted)}#sidebar h2{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:14px}#sidebar input{width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:13px;outline:none;margin-bottom:12px}#sidebar input:focus{border-color:var(--accent)}#sidebar input::placeholder{color:var(--text-dim)}#ontology-list{list-style:none;display:flex;flex-direction:column;gap:2px}.ontology-item{padding:10px 12px;border-radius:6px;cursor:pointer;transition:background .15s}.ontology-item:hover{background:var(--bg-hover)}.ontology-item.active{background:var(--bg-active)}.ontology-item .name{display:block;font-size:13px;font-weight:500;color:var(--text)}.ontology-item .stats{display:block;font-size:11px;color:var(--text-dim);margin-top:2px}.sidebar-edit-btn{position:absolute;right:8px;top:10px;background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;opacity:0;transition:opacity .1s}.ontology-item{position:relative}.ontology-item:hover .sidebar-edit-btn{opacity:.7}.sidebar-section-heading{font-size:10px;font-weight:600;color:var(--text-dim);letter-spacing:.08em;margin:16px 12px 6px}.remote-list{list-style:none;padding:0;margin:0}.ontology-item-remote .name{display:inline}.remote-name-row{display:flex;align-items:center;gap:8px}.remote-badge{font-size:9px;font-weight:600;color:var(--text-dim);background:var(--bg-hover);padding:1px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em;border:1px solid var(--border)}.remote-source{display:block;font-size:10px;color:var(--text-dim);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-edit-btn:hover{opacity:1!important;color:var(--text)}.sidebar-rename-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--text);font:inherit;font-size:13px;font-weight:500;outline:none;width:100%;padding:0}.sidebar-branch{font-size:10px;color:var(--accent);opacity:.7;display:block;margin-top:2px}.sidebar-branch:hover{opacity:1}.sidebar-stale-banner{background:#fff3cd;color:#5c3a00;border:1px solid #e6c263;border-radius:6px;padding:10px 12px;margin-bottom:10px;font-size:11px}.sidebar-stale-banner-title{font-weight:600;margin-bottom:2px}.sidebar-stale-banner-subtitle{opacity:.85;margin-bottom:6px}.sidebar-stale-banner-hint{background:#00000014;border-radius:4px;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;line-height:1.4;margin:0;white-space:pre-wrap;word-break:break-all}.backpack-picker-container{position:relative;margin-bottom:10px}.backpack-picker-pill{display:flex;align-items:center;gap:6px;width:100%;padding:6px 10px;background:var(--bg-base);border:1px solid var(--border);border-radius:6px;color:var(--fg);font-size:11px;font-family:inherit;cursor:pointer;text-align:left}.backpack-picker-pill:hover{border-color:var(--backpack-color, var(--accent))}.backpack-picker-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.backpack-picker-caret{opacity:.6;font-size:10px}.backpack-picker-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px var(--shadow);z-index:50;max-height:300px;overflow-y:auto;padding:4px}.backpack-picker-item{display:flex;align-items:center;gap:6px;width:100%;padding:6px 8px;background:transparent;border:none;border-radius:4px;color:var(--fg);font-family:inherit;font-size:11px;cursor:pointer;text-align:left}.backpack-picker-item:hover{background:var(--bg-hover)}.backpack-picker-item.active{background:var(--bg-hover);font-weight:600}.backpack-picker-item-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-item-name{flex-shrink:0}.backpack-picker-item-path{flex:1;opacity:.55;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;text-align:right}.backpack-picker-divider{height:1px;background:var(--border);margin:4px 0}.backpack-picker-add{opacity:.75;font-style:italic}.sidebar-lock-badge{font-size:10px;color:#c08c00;display:none;margin-top:2px}.sidebar-lock-badge.active{display:block}.sidebar-lock-badge.active:before{content:"● ";color:#c08c00}.sidebar-sync-badge{font-size:10px;color:#5a9fd4;display:none;margin-top:2px}.sidebar-sync-badge.active{display:block}.sidebar-sync-badge.active:before{content:"☁ ";color:#5a9fd4}.branch-picker{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;margin-top:4px;box-shadow:0 4px 16px var(--shadow);z-index:50}.branch-picker-item{display:flex;align-items:center;justify-content:space-between;padding:6px 8px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer}.branch-picker-item:hover{background:var(--bg-hover)}.branch-picker-active{color:var(--accent);font-weight:600;cursor:default}.branch-picker-active:hover{background:none}.branch-picker-delete{background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:14px;padding:0 4px}.sidebar-snippets{margin-top:4px;padding-left:8px}.sidebar-snippet{display:flex;align-items:center;justify-content:space-between;padding:2px 4px;border-radius:4px;cursor:pointer}.sidebar-snippet:hover{background:var(--bg-hover)}.sidebar-snippet-label{font-size:10px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-snippet-delete{background:none;border:none;color:var(--text-dim);font-size:12px;cursor:pointer;padding:0 2px;opacity:0}.sidebar-snippet:hover .sidebar-snippet-delete{opacity:1}.branch-picker-delete:hover{color:var(--danger, #e55)}.branch-picker-create{color:var(--accent);font-size:11px;border-top:1px solid var(--border);margin-top:4px;padding-top:8px}.sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);text-align:center}.sidebar-footer a{display:block;font-size:12px;font-weight:500;color:var(--accent);text-decoration:none;margin-bottom:4px}.sidebar-footer a:hover{color:var(--accent-hover)}.sidebar-footer span{display:block;font-size:10px;color:var(--text-dim)}.sidebar-version{font-size:9px;color:var(--text-dim);opacity:.5;margin-top:4px}.canvas-top-bar{position:absolute;top:16px;left:16px;right:16px;display:flex;justify-content:space-between;align-items:flex-start;pointer-events:none}.canvas-top-left,.canvas-top-right{position:relative;z-index:var(--z-floating);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-center{position:relative;z-index:var(--z-floating-primary);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-left{flex-shrink:0;min-width:var(--tools-width, 264px)}.canvas-top-center{flex:1;justify-content:center}.canvas-bottom-bar{position:absolute;bottom:16px;left:16px;right:16px;display:flex;justify-content:space-between;align-items:flex-end;pointer-events:none;gap:8px}.canvas-bottom-left,.canvas-bottom-center,.canvas-bottom-right{display:flex;align-items:center;gap:4px;pointer-events:auto;position:relative;z-index:var(--z-floating)}.canvas-bottom-center{flex:1;justify-content:center}.focus-indicator{display:flex;align-items:center;gap:2px;background:var(--bg-surface);border:1px solid rgba(212,162,127,.4);border-radius:8px;padding:4px 6px 4px 10px;box-shadow:0 2px 8px var(--shadow)}.focus-indicator-label{font-size:11px;color:var(--accent);font-weight:500;white-space:nowrap;margin-right:4px}.focus-indicator-hops{font-size:11px;color:var(--text-muted);font-family:monospace;min-width:12px;text-align:center}.focus-indicator-btn{background:none;border:none;color:var(--text-muted);font-size:14px;cursor:pointer;padding:2px 4px;line-height:1;border-radius:4px;transition:color .15s,background .15s}.focus-indicator-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover)}.focus-indicator-btn:disabled{color:var(--text-dim);cursor:default;opacity:.3}.focus-indicator-exit{font-size:16px;margin-left:2px}.focus-indicator-exit:hover{color:#ef4444!important}.info-focus-btn{font-size:14px}.theme-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.theme-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.zoom-controls{display:flex;gap:4px}.zoom-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.zoom-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.node-tooltip{position:absolute;pointer-events:none;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:4px 8px;font-size:12px;white-space:nowrap;z-index:20;box-shadow:0 2px 8px #00000026;opacity:.95}#canvas-container{flex:1;position:relative;overflow:hidden;touch-action:none}#graph-canvas{position:absolute;top:0;left:0;touch-action:none;width:100%;height:100%;cursor:grab}#graph-canvas:active{cursor:grabbing}.search-overlay{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;max-height:calc(100vh - 48px);pointer-events:none}.search-overlay>*{pointer-events:auto}.search-overlay.hidden{display:none}.search-input-wrap{position:relative;display:flex;align-items:center;gap:6px;width:380px;max-width:calc(100vw - 340px)}.search-input{flex:1;min-width:0;padding:10px 36px 10px 16px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text);font-size:14px;outline:none;transition:border-color .15s,box-shadow .15s}.search-input:focus{border-color:#d4a27f66;box-shadow:0 0 0 3px #d4a27f1a}.search-input::placeholder{color:var(--text-dim)}.search-kbd{position:absolute;right:10px;top:50%;transform:translateY(-50%);padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg-surface);color:var(--text-dim);font-size:11px;font-family:monospace;pointer-events:none}.search-kbd.hidden{display:none}.search-results{list-style:none;width:380px;max-width:calc(100vw - 340px);background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:10px;overflow:hidden;box-shadow:0 8px 32px var(--shadow-strong)}.search-results.hidden{display:none}.search-result-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .1s}.search-result-item:hover,.search-result-active{background:var(--bg-hover)}.search-result-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.search-result-label{font-size:13px;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-result-type{font-size:11px;color:var(--text-dim);flex-shrink:0}.chip-toggle{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text-dim);cursor:pointer;transition:border-color .15s,color .15s;pointer-events:auto}.chip-toggle:hover{border-color:#d4a27f4d;color:var(--text)}.chip-toggle.active{border-color:#d4a27f66;color:var(--accent)}.type-chips{display:flex;flex-wrap:wrap;gap:4px;justify-content:center;max-width:500px;max-height:200px;overflow-y:auto;padding:4px;border-radius:10px}.type-chips.hidden{display:none}.type-chip{display:flex;align-items:center;gap:4px;padding:3px 10px;border:1px solid transparent;border-radius:12px;background:var(--chip-bg);color:var(--text-dim);font-size:11px;cursor:pointer;transition:all .15s;white-space:nowrap}.type-chip.active{background:var(--chip-bg-active);color:var(--text-muted);border-color:var(--chip-border-active)}.type-chip:hover{background:var(--chip-bg-hover)}.type-chip-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.type-chip:not(.active) .type-chip-dot{opacity:.3}.info-panel-content{flex:1;display:flex;flex-direction:column;min-height:0}.info-panel-header{flex-shrink:0;padding:16px 20px 12px;position:relative}.info-panel-body{flex:1;overflow-y:auto;min-height:0;padding:0 20px 20px}.info-connection-link{cursor:pointer;transition:background .15s}.info-connection-link:hover{background:var(--bg-active)}.info-connection-link .info-target{color:var(--accent);text-decoration:underline;text-decoration-color:transparent;transition:text-decoration-color .15s}.info-connection-link:hover .info-target{text-decoration-color:var(--accent)}.info-header{margin-bottom:16px}.info-type-badge{display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600;color:var(--badge-text);margin-bottom:8px}.info-badge-row{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.info-empty-message{font-size:12px;color:var(--text-dim)}.share-list-message{font-size:13px;color:var(--text-dim);text-align:center;padding:12px}.info-label{font-size:18px;font-weight:600;color:var(--text-strong);margin-bottom:4px;word-break:break-word}.info-id{display:block;font-size:11px;color:var(--text-dim);font-family:monospace}.info-section{margin-bottom:16px}.info-section-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.info-props{display:grid;grid-template-columns:auto 1fr;gap:4px 12px}.info-props dt{font-size:12px;color:var(--text-muted);padding-top:2px}.info-props dd{font-size:12px;color:var(--text);word-break:break-word;display:flex;align-items:center;gap:4px}.info-value{white-space:pre-wrap}.info-array{display:flex;flex-wrap:wrap;gap:4px}.info-tag{display:inline-block;padding:2px 8px;background:var(--bg-hover);border-radius:4px;font-size:11px;color:var(--text-muted)}.info-json{font-size:11px;font-family:monospace;color:var(--text-muted);background:var(--bg-inset);padding:6px 8px;border-radius:4px;overflow-x:auto;white-space:pre}.info-connections{list-style:none;display:flex;flex-direction:column;gap:6px}.info-connection{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--bg-elevated);border-radius:6px;font-size:12px;flex-wrap:wrap}.info-connection-active{outline:1.5px solid var(--accent);background:var(--bg-hover)}.info-target-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.info-arrow{color:var(--text-dim);font-size:14px;flex-shrink:0}.info-edge-type{color:var(--text-muted);font-size:11px;font-weight:500}.info-target{color:var(--text);font-weight:500}.info-edge-props{width:100%;padding-top:4px;padding-left:20px}.info-edge-prop{display:block;font-size:11px;color:var(--text-dim)}.info-editable{cursor:default;position:relative}.info-inline-edit{background:none;border:none;color:var(--badge-text);opacity:0;font-size:10px;cursor:pointer;margin-left:4px;transition:opacity .15s}.info-editable:hover .info-inline-edit{opacity:.8}.info-inline-edit:hover{opacity:1!important}.info-edit-inline-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--badge-text);font:inherit;font-size:inherit;outline:none;width:100%;padding:0}.info-edit-input{background:var(--bg-inset);border:1px solid var(--border);border-radius:4px;padding:3px 6px;font-size:12px;font-family:inherit;color:var(--text);flex:1;min-width:0;resize:vertical;overflow:hidden;line-height:1.4;max-height:300px}.info-edit-input:focus{outline:none;border-color:var(--accent)}.info-delete-prop{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 2px;flex-shrink:0;opacity:0;transition:opacity .1s,color .1s}.info-props dd:hover .info-delete-prop{opacity:1}.info-delete-prop:hover{color:#ef4444}.info-add-btn{background:none;border:1px dashed var(--border);border-radius:4px;padding:6px 10px;font-size:12px;color:var(--text-dim);cursor:pointer;width:100%;margin-top:8px;transition:border-color .15s,color .15s}.info-add-btn:hover{border-color:var(--accent);color:var(--text)}.info-add-row{display:flex;gap:4px;margin-top:6px}.info-add-save{background:var(--accent);border:none;border-radius:4px;padding:3px 10px;font-size:12px;color:var(--badge-text);cursor:pointer;flex-shrink:0}.info-add-save:hover{background:var(--accent-hover)}.info-delete-edge{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;margin-left:auto;padding:0 2px;opacity:0;transition:opacity .1s,color .1s}.info-connection:hover .info-delete-edge{opacity:1}.info-delete-edge:hover{color:#ef4444}.info-danger{margin-top:8px;padding-top:12px;border-top:1px solid var(--border)}.info-delete-node{background:none;border:1px solid rgba(239,68,68,.3);border-radius:6px;padding:6px 12px;font-size:12px;color:#ef4444;cursor:pointer;width:100%;transition:background .15s}.info-delete-node:hover{background:#ef44441a}.tools-pane-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.tools-pane-toggle.hidden{display:none}.tools-pane-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.tools-pane-toggle.active{color:var(--accent);border-color:#d4a27f66}.tools-pane-content{position:absolute;top:56px;left:16px;bottom:16px;z-index:20;width:var(--tools-width, 264px);box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;padding:12px;box-shadow:0 8px 32px var(--shadow)}.tools-pane-content.hidden{display:none}.tools-pane-section{margin-bottom:12px}.tools-pane-section:last-child{margin-bottom:0}.tools-pane-heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-dim);margin-bottom:6px}.tools-pane-row{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:12px}.tools-pane-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.tools-pane-name{flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tools-pane-count{color:var(--text-dim);font-size:11px;flex-shrink:0}.tools-pane-summary{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-muted);padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--border)}.tools-pane-sep{color:var(--text-dim)}.tools-pane-token-card{padding:8px 10px;margin-bottom:10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-hover);font-size:11px}.token-card-label{font-weight:600;color:var(--text);margin-bottom:4px}.token-card-stat{color:var(--text-muted);margin-bottom:4px}.token-card-bar{height:4px;background:var(--border);border-radius:2px;margin:6px 0;overflow:hidden}.token-card-bar-fill{height:100%;background:var(--accent);border-radius:2px;transition:width .3s ease}.tools-pane-clickable{cursor:pointer;border-radius:4px;padding:3px 4px;margin:0 -4px;transition:background .1s}.tools-pane-clickable:hover{background:var(--bg-hover)}.tools-pane-clickable.active{background:var(--bg-hover);outline:1px solid var(--border)}.tools-pane-badge{font-size:9px;color:var(--accent);flex-shrink:0;opacity:.8}.tools-pane-issue .tools-pane-name{color:var(--text-muted)}.tools-pane-more{font-size:10px;color:var(--text-dim);padding:4px 0 0}.tools-pane-edit{background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;padding:0 2px;opacity:0;transition:opacity .1s,color .1s;flex-shrink:0}.tools-pane-row:hover .tools-pane-edit{opacity:1}.tools-pane-edit:hover{color:var(--accent)}.tools-pane-actions{display:flex;gap:6px;padding-top:4px}.tools-pane-action-btn{background:none;border:1px solid var(--border);color:var(--text-muted);font-size:10px;padding:2px 8px;border-radius:3px;cursor:pointer;transition:color .1s,border-color .1s}.tools-pane-action-btn:hover{color:var(--accent);border-color:var(--accent)}.tools-pane-focus-toggle{opacity:.4;font-size:11px}.tools-pane-focus-active{opacity:1!important;color:var(--accent)!important}.tools-pane-focus-clear{margin-top:4px;border-top:1px solid var(--border);padding-top:6px}.tools-pane-editing{background:none!important}.tools-pane-inline-input{width:100%;background:var(--bg);border:1px solid var(--accent);border-radius:4px;color:var(--text);font-size:12px;padding:2px 6px;outline:none}.tools-pane-slider-row{display:flex;align-items:center;gap:6px;padding:4px 0}.tools-pane-slider-label{font-size:11px;color:var(--text-muted);white-space:nowrap;min-width:56px}.tools-pane-slider{flex:1;min-width:0;height:4px;accent-color:var(--accent);cursor:pointer}.tools-pane-slider-value{font-size:10px;color:var(--text-dim);min-width:28px;text-align:right;font-family:monospace}.tools-pane-checkbox{width:14px;height:14px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.tools-pane-export-row{display:flex;gap:4px;margin-top:6px}.tools-pane-export-btn{flex:1;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text-muted);cursor:pointer;transition:color .15s,border-color .15s}.tools-pane-export-btn:hover{color:var(--text);border-color:var(--text-muted)}.tools-pane-empty{font-size:11px;color:var(--text-dim);text-align:center;padding:8px 0}.tools-pane-tabs{display:flex;gap:2px;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}.tools-pane-tab{flex:1;padding:4px 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em;background:none;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;transition:color .15s,background .15s,border-color .15s}.tools-pane-tab:hover{color:var(--text-muted);background:var(--bg-hover)}.tools-pane-tab-active{color:var(--text);background:var(--bg-hover);border-color:var(--border)}.tools-pane-tab-content{flex:1;overflow-y:auto;overflow-x:hidden;min-height:0}.tools-pane-search{width:100%;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);outline:none;margin-bottom:8px;box-sizing:border-box}.tools-pane-search:focus{border-color:var(--accent)}.tools-pane-search::placeholder{color:var(--text-dim)}.tools-pane-empty-msg{font-size:11px;color:var(--text-dim);text-align:center;padding:16px 0}.empty-state{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;z-index:5;pointer-events:none;overflow:hidden}.empty-state.hidden{display:none}.empty-state-bg{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.empty-state-circle{position:absolute;border-radius:50%;background:var(--accent);opacity:.07}.empty-state-circle.c1{width:80px;height:80px;left:20%;top:15%;animation:float-circle 8s ease-in-out infinite}.empty-state-circle.c2{width:50px;height:50px;right:25%;top:25%;animation:float-circle 6s ease-in-out 1s infinite}.empty-state-circle.c3{width:65px;height:65px;left:55%;bottom:20%;animation:float-circle 7s ease-in-out 2s infinite}.empty-state-circle.c4{width:40px;height:40px;left:15%;bottom:30%;animation:float-circle 9s ease-in-out .5s infinite}.empty-state-circle.c5{width:55px;height:55px;right:15%;bottom:35%;animation:float-circle 7.5s ease-in-out 1.5s infinite}.empty-state-lines{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;color:var(--text-dim);animation:float-circle 10s ease-in-out infinite}@keyframes float-circle{0%,to{transform:translateY(0)}50%{transform:translateY(-12px)}}.empty-state-content{text-align:center;max-width:420px;padding:40px 24px;position:relative;z-index:1}.empty-state-icon{color:var(--text-dim);margin-bottom:16px}.empty-state-title{font-size:18px;font-weight:600;color:var(--text);margin-bottom:8px}.empty-state-desc{font-size:13px;color:var(--text-muted);line-height:1.5;margin-bottom:20px}.empty-state-setup{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:12px 16px;margin-bottom:16px}.empty-state-label{font-size:11px;color:var(--text-dim);margin-bottom:8px}.empty-state-code{display:block;font-size:12px;color:var(--accent);font-family:monospace;word-break:break-all}.empty-state-hint{font-size:11px;color:var(--text-dim)}.empty-state-hint kbd{padding:1px 5px;border:1px solid var(--border);border-radius:3px;background:var(--bg-surface);font-family:monospace;font-size:11px}.shortcuts-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100}.shortcuts-overlay.hidden{display:none}.shortcuts-modal{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:24px;min-width:300px;max-width:400px;box-shadow:0 16px 48px var(--shadow);position:relative}.shortcuts-close{position:absolute;top:12px;right:14px;background:none;border:none;color:var(--text-dim);font-size:20px;cursor:pointer;padding:0 4px;line-height:1}.shortcuts-close:hover{color:var(--text)}.shortcuts-title{font-size:15px;font-weight:600;color:var(--text);margin-bottom:16px}.shortcuts-list{display:flex;flex-direction:column;gap:8px}.shortcuts-row{display:flex;align-items:center;justify-content:space-between;gap:12px}.shortcuts-keys{display:flex;align-items:center;gap:4px}.shortcuts-keys kbd{padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--text);font-size:11px;font-family:monospace}.shortcuts-or{font-size:10px;color:var(--text-dim)}.shortcuts-desc{font-size:12px;color:var(--text-muted)}@media(max-width:768px){#app{flex-direction:column}#sidebar{width:100%;min-width:0;max-height:35vh;border-right:none;border-bottom:1px solid var(--border)}.info-panel{top:auto;bottom:72px;right:8px;left:8px;width:auto;max-height:calc(100% - 200px);overflow-y:auto}.info-panel.info-panel-maximized{bottom:0;left:0;right:0}.canvas-top-bar{top:8px;left:8px;right:8px}.canvas-bottom-bar{bottom:8px;left:8px;right:8px}.tools-pane-content{top:48px;left:8px;bottom:80px;width:160px;max-width:calc(100vw - 24px)}.tools-pane-edit{opacity:.6}}.bp-dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.bp-dialog{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:20px;min-width:280px;max-width:400px;box-shadow:0 16px 48px #0000004d}.bp-dialog-title{font-size:14px;font-weight:600;color:var(--text);margin-bottom:12px}.bp-dialog-message{font-size:13px;color:var(--text-muted);margin-bottom:16px;line-height:1.5}.bp-dialog-input{width:100%;padding:8px 12px;font-size:13px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);outline:none;margin-bottom:16px}.bp-dialog-input:focus{border-color:var(--accent)}.bp-dialog-label{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;margin-top:8px;text-transform:uppercase;letter-spacing:.04em}.bp-dialog-path-row{display:flex;gap:8px;margin-bottom:4px}.bp-dialog-path-input{flex:1;margin-bottom:0}.bp-dialog-browse-btn{flex-shrink:0;padding:8px 14px;font-size:12px}.bp-dialog-browse-btn:disabled{opacity:.4;cursor:not-allowed}.bp-dialog-path-input.bp-dialog-drag-over{border-color:var(--accent);background:var(--bg-hover)}.bp-dialog-picker-hint{font-size:11px;color:var(--text-muted);min-height:1em;margin-bottom:8px}.bp-dialog-activate-row{display:flex;align-items:center;gap:8px;margin-top:8px;margin-bottom:12px;font-size:12px;color:var(--text-muted)}.bp-dialog-activate-row input[type=checkbox]{margin:0}.bp-dialog-activate-row label{cursor:pointer}.bp-dialog-buttons{display:flex;justify-content:flex-end;gap:8px}.bp-dialog-btn{padding:6px 16px;font-size:12px;border-radius:6px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);cursor:pointer;transition:all .15s}.bp-dialog-btn:hover{background:var(--bg-hover);color:var(--text)}.bp-dialog-btn-accent{background:var(--accent);color:#fff;border-color:var(--accent)}.bp-dialog-btn-accent:hover{opacity:.9;color:#fff;background:var(--accent)}.bp-dialog-btn-danger{background:#e55;color:#fff;border-color:#e55}.bp-dialog-btn-danger:hover{opacity:.9;color:#fff;background:#e55}.bp-toast{position:fixed;bottom:24px;left:50%;transform:translate(-50%) translateY(20px);background:var(--bg-surface);border:1px solid var(--border);color:var(--text);padding:8px 20px;border-radius:8px;font-size:12px;z-index:1001;opacity:0;transition:opacity .3s,transform .3s;box-shadow:0 4px 16px var(--shadow)}.bp-toast-visible{opacity:1;transform:translate(-50%) translateY(0)}.context-menu{position:absolute;z-index:100;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:180px;box-shadow:0 8px 24px var(--shadow)}.context-menu-item{padding:6px 12px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer;white-space:nowrap}.context-menu-item:hover{background:var(--bg-hover)}.context-menu-separator{height:1px;background:var(--border);margin:4px 8px}.path-bar{display:flex;align-items:center;gap:4px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:6px 12px;box-shadow:0 4px 16px var(--shadow);max-width:80%;overflow-x:auto}.path-bar.hidden{display:none}.path-bar-node{font-size:11px;color:var(--text);padding:2px 8px;border-radius:4px;cursor:pointer;white-space:nowrap;flex-shrink:0}.path-bar-node:hover{background:var(--bg-hover)}.path-bar-edge{font-size:9px;color:var(--text-dim);white-space:nowrap;flex-shrink:0}.path-bar-close{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 4px;margin-left:8px;flex-shrink:0}.path-bar-close:hover{color:var(--text)}.walk-trail-edge{font-size:9px;color:var(--text-dim);padding:1px 0 1px 24px;opacity:.7}.walk-indicator{font-size:10px;color:var(--accent);padding:2px 8px;border:1px solid rgba(212,162,127,.4);border-radius:4px;cursor:pointer;opacity:.4}.walk-indicator.active{opacity:1;background:#d4a27f26;animation:walk-strobe 2s ease-in-out infinite}@keyframes walk-strobe{0%,to{opacity:.6;border-color:#d4a27f4d}50%{opacity:1;border-color:#d4a27fcc}}.copy-prompt-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.copy-prompt-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-top-left,.ext-slot-top-right{display:none;align-items:center;gap:4px}.ext-slot-top-left.has-icons,.ext-slot-top-right.has-icons{display:inline-flex}.ext-slot-bottom-left,.ext-slot-bottom-center,.ext-slot-bottom-right{display:none;flex-direction:row;align-items:center;gap:6px;padding:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 4px 16px var(--shadow)}.ext-slot-bottom-left.has-icons,.ext-slot-bottom-center.has-icons,.ext-slot-bottom-right.has-icons{display:flex}.extension-taskbar-icon{display:inline-flex;align-items:center;gap:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;font-weight:500;font-family:inherit;cursor:pointer;padding:6px 10px;line-height:1;box-shadow:0 2px 8px var(--shadow);transition:color .15s,border-color .15s,background .15s}.ext-slot-bottom-left .extension-taskbar-icon,.ext-slot-bottom-center .extension-taskbar-icon,.ext-slot-bottom-right .extension-taskbar-icon{background:transparent;border-color:transparent;box-shadow:none}.extension-taskbar-icon:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-bottom-left .extension-taskbar-icon:hover,.ext-slot-bottom-center .extension-taskbar-icon:hover,.ext-slot-bottom-right .extension-taskbar-icon:hover{border-color:var(--border)}.extension-taskbar-icon-symbol{font-size:11px;opacity:.7}.extension-taskbar-icon-label{font-size:12px}.extension-panel-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.extension-panel{position:absolute;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 8px 32px var(--shadow);overflow:hidden;pointer-events:auto;width:380px;max-height:calc(100vh - 120px)}.extension-panel.is-fullscreen{top:0!important;left:0!important;right:0;bottom:0;width:auto;max-height:none;border-radius:0}.extension-panel.is-hidden,#canvas-container.has-fullscreen-panel .canvas-top-left,#canvas-container.has-fullscreen-panel .canvas-top-right,#canvas-container.has-fullscreen-panel .canvas-bottom-bar,#canvas-container.has-fullscreen-panel .ext-slot-top-left,#canvas-container.has-fullscreen-panel .ext-slot-top-right{display:none}#canvas-container.has-fullscreen-panel .canvas-top-bar{top:0}#canvas-container.has-fullscreen-panel .extension-panel.is-fullscreen .extension-panel-header{padding-top:56px}.extension-panel.is-fullscreen{border:none;box-shadow:none}.extension-panel-header{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--border);background:var(--bg-surface);flex-shrink:0;cursor:grab;-webkit-user-select:none;user-select:none}.extension-panel-header:active{cursor:grabbing}.extension-panel.is-fullscreen .extension-panel-header{cursor:default}.extension-panel-title{flex:1;font-size:13px;font-weight:500;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extension-panel-custom-btns{display:flex;gap:4px}.extension-panel-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:12px;font-family:inherit;cursor:pointer;padding:3px 8px;line-height:1;min-height:22px;transition:color .15s,background .15s,border-color .15s}.extension-panel-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover);border-color:var(--text-muted)}.extension-panel-btn:disabled{opacity:.4;cursor:not-allowed}.extension-panel-btn-fullscreen{padding:2px 6px}.extension-panel-btn-fullscreen svg{display:block}.extension-panel-btn-close{font-size:16px;padding:0 7px}.extension-panel-body{flex:1;overflow:hidden;display:flex;flex-direction:column}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var Jn=Object.defineProperty;var Kn=(t,e,s)=>e in t?Jn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var At=(t,e,s)=>Kn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))l(m);new MutationObserver(m=>{for(const r of m)if(r.type==="childList")for(const d of r.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&l(d)}).observe(document,{childList:!0,subtree:!0});function s(m){const r={};return m.integrity&&(r.integrity=m.integrity),m.referrerPolicy&&(r.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?r.credentials="include":m.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function l(m){if(m.ep)return;m.ep=!0;const r=s(m);fetch(m.href,r)}})();const Zn="modulepreload",Qn=function(t){return"/"+t},hn={},eo=function(e,s,l){let m=Promise.resolve();if(s&&s.length>0){let d=function(g){return Promise.all(g.map(i=>Promise.resolve(i).then(c=>({status:"fulfilled",value:c}),c=>({status:"rejected",reason:c}))))};document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),n=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));m=d(s.map(g=>{if(g=Qn(g),g in hn)return;hn[g]=!0;const i=g.endsWith(".css"),c=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${g}"]${c}`))return;const I=document.createElement("link");if(I.rel=i?"stylesheet":Zn,i||(I.as="script"),I.crossOrigin="",I.href=g,n&&I.setAttribute("nonce",n),document.head.appendChild(I),i)return new Promise((M,x)=>{I.addEventListener("load",M),I.addEventListener("error",()=>x(new Error(`Unable to preload CSS for ${g}`)))})}))}function r(d){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=d,window.dispatchEvent(o),!o.defaultPrevented)throw d}return m.then(d=>{for(const o of d||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})};async function vt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function Pt(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function to(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function no(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function zt(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function oo(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function so(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function fn(t,e,s){const l=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!l.ok){const m=await l.json().catch(()=>({}));throw new Error(m.error||"Failed to create branch")}}async function gn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to switch branch")}}async function ao(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to delete branch")}}async function co(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function io(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to create snapshot")}}async function lo(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to rollback")}}async function ro(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function yn(t,e,s,l,m){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:m,nodeIds:s,edgeIds:l})});if(!r.ok)throw new Error("Failed to save snippet");return(await r.json()).id}async function po(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function uo(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const Cn="bp-dialog-overlay";function nn(){var e;(e=document.querySelector(`.${Cn}`))==null||e.remove();const t=document.createElement("div");return t.className=Cn,document.body.appendChild(t),t}function on(t,e){const s=document.createElement("div");s.className="bp-dialog";const l=document.createElement("h4");return l.className="bp-dialog-title",l.textContent=e,s.appendChild(l),t.appendChild(s),t.addEventListener("click",m=>{m.target===t&&t.remove()}),s}function sn(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const l of e){const m=document.createElement("button");m.className="bp-dialog-btn",l.accent&&m.classList.add("bp-dialog-btn-accent"),l.danger&&m.classList.add("bp-dialog-btn-danger"),m.textContent=l.label,m.addEventListener("click",l.onClick),s.appendChild(m)}t.appendChild(s)}function jn(t,e){return new Promise(s=>{var d;const l=nn(),m=on(l,t),r=document.createElement("p");r.className="bp-dialog-message",r.textContent=e,m.appendChild(r),sn(m,[{label:"Cancel",onClick:()=>{l.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{l.remove(),s(!0)}}]),(d=m.querySelector(".bp-dialog-btn-accent"))==null||d.focus()})}function Dt(t,e,s){return new Promise(l=>{const m=nn(),r=on(m,t),d=document.createElement("input");d.type="text",d.className="bp-dialog-input",d.placeholder=e??"",d.value="",r.appendChild(d);const o=()=>{const n=d.value.trim();m.remove(),l(n||null)};d.addEventListener("keydown",n=>{n.key==="Enter"&&o(),n.key==="Escape"&&(m.remove(),l(null))}),sn(r,[{label:"Cancel",onClick:()=>{m.remove(),l(null)}},{label:"OK",accent:!0,onClick:o}]),d.focus(),d.select()})}function mo(){return new Promise(t=>{const e=nn(),s=on(e,"Add Backpack"),l=document.createElement("p");l.className="bp-dialog-message",l.textContent="Enter the absolute path to a directory that should become a backpack. It will be shown in the sidebar using the last segment of the path as its display name.",s.appendChild(l);const m=document.createElement("label");m.className="bp-dialog-label",m.textContent="Path",s.appendChild(m);const r=document.createElement("div");r.className="bp-dialog-path-row",s.appendChild(r);const d=document.createElement("input");d.type="text",d.className="bp-dialog-input bp-dialog-path-input",d.placeholder="/Users/you/OneDrive/work",r.appendChild(d);const o=document.createElement("button");o.type="button",o.className="bp-dialog-btn bp-dialog-browse-btn",o.textContent="Browse...",r.appendChild(o),typeof window.showDirectoryPicker=="function"||(o.disabled=!0,o.title="Browser doesn't support native folder picker — paste the path manually"),o.addEventListener("click",async x=>{x.preventDefault();try{const F=await window.showDirectoryPicker({mode:"read"});g.textContent=`Picked "${F.name}" — paste the absolute path to it below.`,d.focus()}catch{}});const g=document.createElement("div");g.className="bp-dialog-picker-hint",s.appendChild(g);const i=document.createElement("div");i.className="bp-dialog-activate-row";const c=document.createElement("input");c.type="checkbox",c.id="bp-dialog-activate",c.checked=!0;const I=document.createElement("label");I.htmlFor="bp-dialog-activate",I.textContent="Switch to this backpack after registering",i.appendChild(c),i.appendChild(I),s.appendChild(i),d.addEventListener("dragover",x=>{x.preventDefault(),d.classList.add("bp-dialog-drag-over")}),d.addEventListener("dragleave",()=>{d.classList.remove("bp-dialog-drag-over")}),d.addEventListener("drop",x=>{var V,_,X;x.preventDefault(),d.classList.remove("bp-dialog-drag-over");const F=(V=x.dataTransfer)==null?void 0:V.items;if(!F||F.length===0)return;const W=(X=(_=F[0]).webkitGetAsEntry)==null?void 0:X.call(_);W!=null&&W.isDirectory&&(g.textContent=`Dropped "${W.name}" — paste the absolute path to it below.`)});const M=()=>{const x=d.value.trim();x&&(e.remove(),t({path:x,activate:c.checked}))};d.addEventListener("keydown",x=>{x.key==="Enter"&&M(),x.key==="Escape"&&(e.remove(),t(null))}),sn(s,[{label:"Cancel",onClick:()=>{e.remove(),t(null)}},{label:"Register",accent:!0,onClick:M}]),d.focus()})}function kt(t,e=3e3){const s=document.querySelector(".bp-toast");s&&s.remove();const l=document.createElement("div");l.className="bp-toast",l.textContent=t,document.body.appendChild(l),setTimeout(()=>l.classList.add("bp-toast-visible"),10),setTimeout(()=>{l.classList.remove("bp-toast-visible"),setTimeout(()=>l.remove(),300)},e)}const bn="http://www.w3.org/2000/svg";function at(t,e){const s=document.createElementNS(bn,"svg"),l=t.size??16;s.setAttribute("width",String(l)),s.setAttribute("height",String(l)),s.setAttribute("viewBox",t.viewBox??"0 0 24 24"),s.setAttribute("fill","none"),s.setAttribute("stroke","currentColor"),s.setAttribute("stroke-width",String(t.strokeWidth??2)),t.strokeLinecap&&s.setAttribute("stroke-linecap",t.strokeLinecap),t.strokeLinejoin&&s.setAttribute("stroke-linejoin",t.strokeLinejoin),t.className&&s.setAttribute("class",t.className);for(const m of e){const r=document.createElementNS(bn,m.tag);for(const[d,o]of Object.entries(m.attrs))r.setAttribute(d,String(o));s.appendChild(r)}return s}function ho(t){return Array.from(t.childNodes).map(e=>e.cloneNode(!0))}function fo(t,e){t.replaceChildren(...e)}function vn(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function xn(t,e){return t*50+e*25+50}function go(t,e){const s=typeof e=="function"?{onSelect:e}:e,l=document.createElement("h2");l.textContent="Backpack Viewer";const m=document.createElement("input");m.type="text",m.placeholder="Filter...",m.id="filter";const r=document.createElement("ul");r.id="ontology-list";const d=document.createElement("h3");d.className="sidebar-section-heading",d.textContent="REMOTE GRAPHS",d.hidden=!0;const o=document.createElement("ul");o.id="remote-list",o.className="remote-list",o.hidden=!0;const n=document.createElement("div");n.className="sidebar-footer";const g=document.createElement("a");g.href="mailto:support@backpackontology.com",g.textContent="support@backpackontology.com";const i=document.createElement("span");i.textContent="Feedback & support";const c=document.createElement("span");c.className="sidebar-version",c.textContent="v0.7.15",n.append(g,i,c);const I=document.createElement("button");I.className="sidebar-collapse-btn",I.title="Toggle sidebar (Tab)",I.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"11 17 6 12 11 7"}},{tag:"polyline",attrs:{points:"18 17 13 12 18 7"}}]));let M=!1;function x(){M=!M,t.classList.toggle("sidebar-collapsed",M),ye.classList.toggle("hidden",!M)}I.addEventListener("click",x);const F=document.createElement("div");F.className="sidebar-heading-row",F.appendChild(l),F.appendChild(I),t.appendChild(F);const W=document.createElement("div");W.className="sidebar-stale-banner",W.hidden=!0,t.appendChild(W);const V=document.createElement("button");V.className="backpack-picker-pill",V.type="button",V.setAttribute("aria-haspopup","listbox"),V.setAttribute("aria-expanded","false");const _=document.createElement("span");_.className="backpack-picker-dot";const X=document.createElement("span");X.className="backpack-picker-name",X.textContent="...";const Y=document.createElement("span");Y.className="backpack-picker-caret",Y.textContent="▾",V.appendChild(_),V.appendChild(X),V.appendChild(Y);const Z=document.createElement("div");Z.className="backpack-picker-dropdown",Z.hidden=!0,Z.setAttribute("role","listbox");const q=document.createElement("div");q.className="backpack-picker-container",q.appendChild(V),q.appendChild(Z),t.appendChild(q);let me=!1;function U(){me=!1,Z.hidden=!0,V.setAttribute("aria-expanded","false")}function pe(){me=!0,Z.hidden=!1,V.setAttribute("aria-expanded","true")}V.addEventListener("click",p=>{p.stopPropagation(),me?U():pe()}),document.addEventListener("click",p=>{q.contains(p.target)||U()});let Ee=[],te=null;function G(){Z.replaceChildren();for(const E of Ee){const u=document.createElement("button");u.className="backpack-picker-item",u.type="button",u.setAttribute("role","option"),E.active&&u.classList.add("active");const b=document.createElement("span");b.className="backpack-picker-item-dot",b.style.setProperty("--backpack-color",E.color);const S=document.createElement("span");S.className="backpack-picker-item-name",S.textContent=E.name;const h=document.createElement("span");h.className="backpack-picker-item-path",h.textContent=E.path,u.appendChild(b),u.appendChild(S),u.appendChild(h),u.addEventListener("click",T=>{T.stopPropagation(),U(),!E.active&&s.onBackpackSwitch&&s.onBackpackSwitch(E.name)}),Z.appendChild(u)}const p=document.createElement("div");p.className="backpack-picker-divider",Z.appendChild(p);const C=document.createElement("button");C.className="backpack-picker-item backpack-picker-add",C.type="button",C.textContent="+ Add new backpack…",C.addEventListener("click",async E=>{if(E.stopPropagation(),U(),!s.onBackpackRegister)return;const u=await mo();u&&s.onBackpackRegister(u.path,u.activate)}),Z.appendChild(C)}const ye=document.createElement("button");ye.className="tools-pane-toggle hidden",ye.title="Show sidebar (Tab)",ye.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"13 7 18 12 13 17"}},{tag:"polyline",attrs:{points:"6 7 11 12 6 17"}}])),ye.addEventListener("click",x),t.appendChild(m),t.appendChild(r),t.appendChild(d),t.appendChild(o),t.appendChild(n);let Ce=[],se=[],ge="";return m.addEventListener("input",()=>{const p=m.value.toLowerCase();for(const C of Ce){const E=C.dataset.name??"";C.style.display=E.includes(p)?"":"none"}for(const C of se){const E=C.dataset.name??"";C.style.display=E.includes(p)?"":"none"}}),{setStaleVersionBanner(p,C){W.replaceChildren();const E=document.createElement("div");E.className="sidebar-stale-banner-title",E.textContent=`Viewer ${p} is out of date`;const u=document.createElement("div");u.className="sidebar-stale-banner-subtitle",u.textContent=`Latest is ${C}. Your version is stuck because of an npx cache.`;const b=document.createElement("pre");b.className="sidebar-stale-banner-hint",b.textContent=`npm cache clean --force
|
|
2
|
+
npx backpack-viewer@latest`,W.appendChild(E),W.appendChild(u),W.appendChild(b),W.hidden=!1},setBackpacks(p){Ee=p.slice();const C=p.find(E=>E.active)??null;te=C,C&&(X.textContent=C.name,_.style.setProperty("--backpack-color",C.color),t.style.setProperty("--backpack-color",C.color)),G()},setActiveBackpack(p){te=p,Ee=Ee.map(C=>({...C,active:C.name===p.name})),Ee.some(C=>C.name===p.name)||Ee.push({...p,active:!0}),X.textContent=p.name,_.style.setProperty("--backpack-color",p.color),t.style.setProperty("--backpack-color",p.color),G()},getActiveBackpack(){return te},setSummaries(p){r.replaceChildren();const C=fetch("/api/locks").then(u=>u.json()).catch(()=>({})),E=fetch("/api/sync-status").then(u=>u.json()).then(u=>new Set(u.synced)).catch(()=>new Set);Ce=p.map(u=>{const b=document.createElement("li");b.className="ontology-item",b.dataset.name=u.name;const S=document.createElement("span");S.className="name",S.textContent=u.name;const h=document.createElement("span");h.className="stats";const T=xn(u.nodeCount,u.edgeCount);h.textContent=`${u.nodeCount} nodes, ${u.edgeCount} edges · ~${vn(T)}`;const w=document.createElement("span");w.className="sidebar-branch",w.dataset.graph=u.name;const N=document.createElement("span");N.className="sidebar-lock-badge",N.dataset.graph=u.name,C.then(y=>{if(!N.isConnected)return;const P=y[u.name];P&&typeof P=="object"&&P.author&&(N.textContent=`editing: ${P.author}`,N.title=`Last activity: ${P.lastActivity??""}`,N.classList.add("active"))});const L=document.createElement("span");if(L.className="sidebar-sync-badge",L.dataset.graph=u.name,E.then(y=>{L.isConnected&&y.has(u.name)&&(L.textContent="synced",L.title="This graph has been synced",L.classList.add("active"))}),b.appendChild(S),b.appendChild(h),b.appendChild(N),b.appendChild(L),b.appendChild(w),s.onRename){const y=document.createElement("button");y.className="sidebar-edit-btn",y.textContent="✎",y.title="Rename";const P=s.onRename;y.addEventListener("click",$=>{$.stopPropagation();const K=document.createElement("input");K.type="text",K.className="sidebar-rename-input",K.value=u.name,S.textContent="",S.appendChild(K),y.style.display="none",K.focus(),K.select();const ae=()=>{const ce=K.value.trim();ce&&ce!==u.name?P(u.name,ce):(S.textContent=u.name,y.style.display="")};K.addEventListener("blur",ae),K.addEventListener("keydown",ce=>{ce.key==="Enter"&&K.blur(),ce.key==="Escape"&&(K.value=u.name,K.blur())})}),b.appendChild(y)}return b.addEventListener("click",()=>s.onSelect(u.name)),r.appendChild(b),b}),ge&&this.setActive(ge)},setActive(p){ge=p;for(const C of Ce)C.classList.toggle("active",C.dataset.name===p);for(const C of se)C.classList.toggle("active",C.dataset.name===p)},setRemotes(p){o.replaceChildren(),se=p.map(E=>{const u=document.createElement("li");u.className="ontology-item ontology-item-remote",u.dataset.name=E.name;const b=document.createElement("div");b.className="remote-name-row";const S=document.createElement("span");S.className="name",S.textContent=E.name;const h=document.createElement("span");h.className="remote-badge",h.textContent=E.pinned?"remote · pinned":"remote",h.title=`Source: ${E.source??E.url}`,b.appendChild(S),b.appendChild(h);const T=document.createElement("span");T.className="stats";const w=xn(E.nodeCount,E.edgeCount);T.textContent=`${E.nodeCount} nodes, ${E.edgeCount} edges · ~${vn(w)}`;const N=document.createElement("span");return N.className="remote-source",N.textContent=E.source??new URL(E.url).hostname,N.title=E.url,u.appendChild(b),u.appendChild(T),u.appendChild(N),u.addEventListener("click",()=>s.onSelect(E.name)),o.appendChild(u),u});const C=p.length>0;d.hidden=!C,o.hidden=!C,ge&&this.setActive(ge)},setActiveBranch(p,C,E){const u=r.querySelectorAll(`.sidebar-branch[data-graph="${p}"]`);for(const b of u){b.textContent=`/ ${C}`,b.title="Click to switch branch",b.style.cursor="pointer";const S=b.cloneNode(!0);b.replaceWith(S),S.addEventListener("click",h=>{h.stopPropagation(),be(p,S,E??[])})}},setSnippets(p,C){var b;const E=Ce.find(S=>S.dataset.name===p);if(!E||((b=E.querySelector(".sidebar-snippets"))==null||b.remove(),C.length===0))return;const u=document.createElement("div");u.className="sidebar-snippets";for(const S of C){const h=document.createElement("div");h.className="sidebar-snippet";const T=document.createElement("span");T.className="sidebar-snippet-label",T.textContent=`◆ ${S.label}`,T.title=`${S.nodeCount} nodes — click to load`;const w=document.createElement("button");w.className="sidebar-snippet-delete",w.textContent="×",w.title="Delete snippet",w.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetDelete)==null||L.call(s,p,S.id)}),h.appendChild(T),h.appendChild(w),h.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetLoad)==null||L.call(s,p,S.id)}),u.appendChild(h)}E.appendChild(u)},toggle:x,expandBtn:ye};function be(p,C,E){const u=t.querySelector(".branch-picker");u&&u.remove();const b=document.createElement("div");b.className="branch-picker";for(const h of E){const T=document.createElement("div");T.className="branch-picker-item",h.active&&T.classList.add("branch-picker-active");const w=document.createElement("span");if(w.textContent=h.name,T.appendChild(w),!h.active&&s.onBranchDelete){const N=document.createElement("button");N.className="branch-picker-delete",N.textContent="×",N.title=`Delete ${h.name}`,N.addEventListener("click",L=>{L.stopPropagation(),jn("Delete branch",`Delete branch "${h.name}"?`).then(y=>{y&&(s.onBranchDelete(p,h.name),b.remove())})}),T.appendChild(N)}h.active||T.addEventListener("click",()=>{var N;(N=s.onBranchSwitch)==null||N.call(s,p,h.name),b.remove()}),b.appendChild(T)}if(s.onBranchCreate){const h=document.createElement("div");h.className="branch-picker-item branch-picker-create",h.textContent="+ New branch",h.addEventListener("click",()=>{Dt("New branch","Branch name").then(T=>{T&&(s.onBranchCreate(p,T),b.remove())})}),b.appendChild(h)}C.after(b);const S=h=>{b.contains(h.target)||(b.remove(),document.removeEventListener("click",S))};setTimeout(()=>document.addEventListener("click",S),0)}}function Zt(t,e,s,l){return{x0:t,y0:e,x1:s,y1:l,cx:0,cy:0,mass:0,children:[null,null,null,null],body:null}}function En(t,e,s){const l=(t.x0+t.x1)/2,m=(t.y0+t.y1)/2;return(e<l?0:1)+(s<m?0:2)}function wn(t,e){const s=(t.x0+t.x1)/2,l=(t.y0+t.y1)/2;switch(e){case 0:return[t.x0,t.y0,s,l];case 1:return[s,t.y0,t.x1,l];case 2:return[t.x0,l,s,t.y1];default:return[s,l,t.x1,t.y1]}}function Qt(t,e){if(t.mass===0&&t.body===null){t.body=e,t.cx=e.x,t.cy=e.y,t.mass=1;return}if(t.body!==null){const m=t.body;t.body=null,m.x===e.x&&m.y===e.y&&(e.x+=(Math.random()-.5)*.1,e.y+=(Math.random()-.5)*.1);const r=En(t,m.x,m.y);if(t.children[r]===null){const[d,o,n,g]=wn(t,r);t.children[r]=Zt(d,o,n,g)}Qt(t.children[r],m)}const s=En(t,e.x,e.y);if(t.children[s]===null){const[m,r,d,o]=wn(t,s);t.children[s]=Zt(m,r,d,o)}Qt(t.children[s],e);const l=t.mass+1;t.cx=(t.cx*t.mass+e.x)/l,t.cy=(t.cy*t.mass+e.y)/l,t.mass=l}function yo(t){if(t.length===0)return null;let e=1/0,s=1/0,l=-1/0,m=-1/0;for(const i of t)i.x<e&&(e=i.x),i.y<s&&(s=i.y),i.x>l&&(l=i.x),i.y>m&&(m=i.y);const r=Math.max(l-e,m-s)*.1+50,d=(e+l)/2,o=(s+m)/2,n=Math.max(l-e,m-s)/2+r,g=Zt(d-n,o-n,d+n,o+n);for(const i of t)Qt(g,i);return g}function Co(t,e,s,l,m,r){zn(t,e,s,l,m,r)}function zn(t,e,s,l,m,r){if(t.mass===0)return;const d=t.cx-e.x,o=t.cy-e.y,n=d*d+o*o;if(t.body!==null){if(t.body!==e){let i=Math.sqrt(n);i<r&&(i=r);const c=l*m/(i*i),I=d/i*c,M=o/i*c;e.vx-=I,e.vy-=M}return}const g=t.x1-t.x0;if(g*g/n<s*s){let i=Math.sqrt(n);i<r&&(i=r);const c=l*t.mass*m/(i*i),I=d/i*c,M=o/i*c;e.vx-=I,e.vy-=M;return}for(let i=0;i<4;i++)t.children[i]!==null&&zn(t.children[i],e,s,l,m,r)}const _n={clusterStrength:.08,spacing:1.5},kn=6e3,bo=12e3,vo=.004,Hn=140,Yn=350,Sn=.9,Nn=.01,xt=30,_t=50;let Ze={..._n};function lt(t){t.clusterStrength!==void 0&&(Ze.clusterStrength=t.clusterStrength),t.spacing!==void 0&&(Ze.spacing=t.spacing)}function wt(){return{...Ze}}function xo(t){if(t<=30)return{..._n};const e=Math.log2(t/30);return{clusterStrength:Math.min(.5,.08+.06*e),spacing:Math.min(15,1.5+1.2*e)}}function Eo(t,e){for(const s of Object.values(t))if(typeof s=="string")return s;return e}function Ln(t,e,s){const l=new Set(e);let m=new Set(e);for(let r=0;r<s;r++){const d=new Set;for(const o of t.edges)m.has(o.sourceId)&&!l.has(o.targetId)&&d.add(o.targetId),m.has(o.targetId)&&!l.has(o.sourceId)&&d.add(o.sourceId);for(const o of d)l.add(o);if(m=d,d.size===0)break}return{nodes:t.nodes.filter(r=>l.has(r.id)),edges:t.edges.filter(r=>l.has(r.sourceId)&&l.has(r.targetId)),metadata:t.metadata}}function Ht(t){const e=new Map,s=[...new Set(t.nodes.map(n=>n.type))],l=Math.sqrt(s.length)*Yn*.6*Math.max(1,Ze.spacing),m=new Map,r=new Map;for(const n of t.nodes)r.set(n.type,(r.get(n.type)??0)+1);const d=t.nodes.map(n=>{const g=s.indexOf(n.type),i=2*Math.PI*g/Math.max(s.length,1),c=Math.cos(i)*l,I=Math.sin(i)*l,M=m.get(n.type)??0;m.set(n.type,M+1);const x=r.get(n.type)??1,F=2*Math.PI*M/x,W=Hn*.6,V={id:n.id,x:c+Math.cos(F)*W,y:I+Math.sin(F)*W,vx:0,vy:0,label:Eo(n.properties,n.id),type:n.type};return e.set(n.id,V),V}),o=t.edges.map(n=>({sourceId:n.sourceId,targetId:n.targetId,type:n.type}));return{nodes:d,edges:o,nodeMap:e}}const wo=.7,ko=80;function So(t,e){const{nodes:s,edges:l,nodeMap:m}=t,r=bo*Ze.spacing;if(s.length>=ko){const o=yo(s);if(o)for(const g of s)Co(o,g,wo,r,e,xt);const n=r-kn;if(n>0){const g=new Map;for(const i of s){let c=g.get(i.type);c||(c=[],g.set(i.type,c)),c.push(i)}for(const i of g.values())for(let c=0;c<i.length;c++)for(let I=c+1;I<i.length;I++){const M=i[c],x=i[I];let F=x.x-M.x,W=x.y-M.y,V=Math.sqrt(F*F+W*W);V<xt&&(V=xt);const _=n*e/(V*V),X=F/V*_,Y=W/V*_;M.vx+=X,M.vy+=Y,x.vx-=X,x.vy-=Y}}}else for(let o=0;o<s.length;o++)for(let n=o+1;n<s.length;n++){const g=s[o],i=s[n];let c=i.x-g.x,I=i.y-g.y,M=Math.sqrt(c*c+I*I);M<xt&&(M=xt);const F=(g.type===i.type?kn:r)*e/(M*M),W=c/M*F,V=I/M*F;g.vx-=W,g.vy-=V,i.vx+=W,i.vy+=V}for(const o of l){const n=m.get(o.sourceId),g=m.get(o.targetId);if(!n||!g)continue;const i=g.x-n.x,c=g.y-n.y,I=Math.sqrt(i*i+c*c);if(I===0)continue;const M=n.type===g.type?Hn*Ze.spacing:Yn*Ze.spacing,x=vo*(I-M)*e,F=i/I*x,W=c/I*x;n.vx+=F,n.vy+=W,g.vx-=F,g.vy-=W}for(const o of s)o.vx-=o.x*Nn*e,o.vy-=o.y*Nn*e;const d=new Map;for(const o of s){const n=d.get(o.type)??{x:0,y:0,count:0};n.x+=o.x,n.y+=o.y,n.count++,d.set(o.type,n)}for(const o of d.values())o.x/=o.count,o.y/=o.count;for(const o of s){const n=d.get(o.type);o.vx+=(n.x-o.x)*Ze.clusterStrength*e,o.vy+=(n.y-o.y)*Ze.clusterStrength*e}for(const o of s){if(o.pinned){o.vx=0,o.vy=0;continue}o.vx*=Sn,o.vy*=Sn;const n=Math.sqrt(o.vx*o.vx+o.vy*o.vy);n>_t&&(o.vx=o.vx/n*_t,o.vy=o.vy/n*_t),o.x+=o.vx,o.y+=o.vy}return e*.995}const In=["#d4a27f","#c17856","#b07a5e","#d4956b","#a67c5a","#cc9e7c","#c4866a","#cb8e6c","#b8956e","#a88a70","#d9b08c","#c4a882","#e8b898","#b5927a","#a8886e","#d1a990"],Mn=new Map;function Ae(t){const e=Mn.get(t);if(e)return e;let s=0;for(let m=0;m<t.length;m++)s=(s<<5)-s+t.charCodeAt(m)|0;const l=In[Math.abs(s)%In.length];return Mn.set(t,l),l}class No{constructor(e){At(this,"cells",new Map);At(this,"cellSize");At(this,"invCell");this.cellSize=e,this.invCell=1/e}key(e,s){const l=e+32768|0,m=s+32768|0;return l*73856093^m*19349663}clear(){this.cells.clear()}insert(e){const s=Math.floor(e.x*this.invCell),l=Math.floor(e.y*this.invCell),m=this.key(s,l),r=this.cells.get(m);r?r.push(e):this.cells.set(m,[e])}rebuild(e){this.cells.clear();for(const s of e)this.insert(s)}query(e,s,l){const m=l*l,r=Math.floor((e-l)*this.invCell),d=Math.floor((e+l)*this.invCell),o=Math.floor((s-l)*this.invCell),n=Math.floor((s+l)*this.invCell);let g=null,i=m;for(let c=r;c<=d;c++)for(let I=o;I<=n;I++){const M=this.cells.get(this.key(c,I));if(M)for(const x of M){const F=x.x-e,W=x.y-s,V=F*F+W*W;V<=i&&(i=V,g=x)}}return g}}const pt=new Map,Lo=2e3;function Io(t,e,s){return`${t}|${e}|${s}`}const Mo=new OffscreenCanvas(1,1),Tn=Mo.getContext("2d");function To(t,e,s){Tn.font=e;const l=Tn.measureText(t),m=Math.ceil(l.width)+2,r=Math.ceil(l.actualBoundingBoxAscent+l.actualBoundingBoxDescent)+4,d=new OffscreenCanvas(m,r),o=d.getContext("2d");return o.font=e,o.fillStyle=s,o.textAlign="left",o.textBaseline="top",o.fillText(t,1,1),{canvas:d,width:m,height:r}}function An(t,e,s,l,m,r,d){const o=Io(e,m,r);let n=pt.get(o);if(!n){if(pt.size>=Lo){const c=pt.keys().next().value;c!==void 0&&pt.delete(c)}n=To(e,m,r),pt.set(o,n)}const g=s-n.width/2,i=d==="top"?l:l-n.height;t.drawImage(n.canvas,g,i)}function Ao(){pt.clear()}function we(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}const Ue=20,Yt=.001,Po={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15,dotNodes:.1,hullsOnly:.05},Ro={zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300};function Rt(t,e,s,l,m,r=100){const d=(t-s.x)*s.scale,o=(e-s.y)*s.scale;return d>=-r&&d<=l+r&&o>=-r&&o<=m+r}function Bo(t,e,s,l){const m={...Po,...(l==null?void 0:l.lod)??{}},r={...Ro,...(l==null?void 0:l.navigation)??{}},d={pulseSpeed:.02,...(l==null?void 0:l.walk)??{}},o=t.querySelector("canvas"),n=o.getContext("2d"),g=window.devicePixelRatio||1;let i={x:0,y:0,scale:1},c=null,I=1,M=0,x=new Set,F=null,W=!0,V=!0,_=!0,X=!0,Y="idle",Z=[],q=0,me=0,U=null,pe=new Set;const Ee=5;let te=null,G=null,ye=1,Ce=null,se=null,ge=null,be=!1,p=[],C=0,E=0;const u=400,b=new No(Ue*2);let S=0;function h(){ae(),S||(S=requestAnimationFrame(()=>{S=0,Xe()}))}const T=150;let w=null,N=!1;function L(){if(!w)try{w=new Worker(new URL("/assets/layout-worker-4xak23M6.js",import.meta.url),{type:"module"}),w.onmessage=y,w.onerror=()=>{N=!1,w=null,j()}}catch{return N=!1,null}return w}function y(f){const k=f.data;if(k.type==="tick"&&c){const B=k.positions,D=c.nodes;for(let H=0;H<D.length;H++)D[H].x=B[H*4],D[H].y=B[H*4+1],D[H].vx=B[H*4+2],D[H].vy=B[H*4+3];I=k.alpha,b.rebuild(D),Xe()}k.type==="settled"&&(I=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(v)))}let P=null,$=null,K=!0;function ae(){K=!0}let ce=null,ue=null;const ve=r.panAnimationMs;function $e(){o.width=o.clientWidth*g,o.height=o.clientHeight*g,ae(),h()}const Qe=new ResizeObserver($e);Qe.observe(t),$e();function Re(f,k){return[f/i.scale+i.x,k/i.scale+i.y]}function et(f,k){if(!c)return null;const[B,D]=Re(f,k);return b.query(B,D,Ue)}function ct(){if(!U)return;n.save();const f=Math.min(U.x1,U.x2),k=Math.max(U.x1,U.x2),B=Math.min(U.y1,U.y2),D=Math.max(U.y1,U.y2);n.strokeStyle=we("--accent")||"#d4a27f",n.fillStyle=we("--accent")||"#d4a27f",n.globalAlpha=.12,n.fillRect(f,B,k-f,D-B),n.globalAlpha=.8,n.lineWidth=1/Math.max(i.scale,.5),n.setLineDash([6/Math.max(i.scale,.5),4/Math.max(i.scale,.5)]),n.strokeRect(f,B,k-f,D-B),n.setLineDash([]),n.restore()}function Ot(){if(!c)return;C+=d.pulseSpeed;const f=new Set(p);n.save(),n.setTransform(g,0,0,g,0,0),P&&(n.clearRect(0,0,o.clientWidth,o.clientHeight),n.drawImage(P,0,0,o.clientWidth,o.clientHeight)),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale);const k=we("--canvas-walk-edge")||"#1a1a1a",B=[];for(const z of c.edges){if(!f.has(z.sourceId)||!f.has(z.targetId)||z.sourceId===z.targetId)continue;const O=c.nodeMap.get(z.sourceId),J=c.nodeMap.get(z.targetId);!O||!J||B.push(O.x,O.y,J.x,J.y)}if(B.length>0){n.beginPath();for(let z=0;z<B.length;z+=4)n.moveTo(B[z],B[z+1]),n.lineTo(B[z+2],B[z+3]);n.strokeStyle=k,n.lineWidth=3,n.globalAlpha=.5+.5*Math.sin(C),n.stroke(),n.globalAlpha=1}const D=i.scale<m.smallNodes?Ue*.5:Ue,H=we("--accent")||"#d4a27f";for(const z of p){const O=c.nodeMap.get(z);if(!O||!Rt(O.x,O.y,i,o.clientWidth,o.clientHeight))continue;const J=z===p[p.length-1],Q=.5+.5*Math.sin(C);n.strokeStyle=H,n.lineWidth=J?3:2,n.globalAlpha=J?.5+.5*Q:.3+.4*Q,n.beginPath(),n.arc(O.x,O.y,D+(J?6:4),0,Math.PI*2),n.stroke()}n.globalAlpha=1,ct(),n.restore(),X&&c.nodes.length>1&&Wt(),n.restore()}function Xe(){var ln;if(!c){n.clearRect(0,0,o.width,o.height);return}if(!K&&P&&be&&p.length>0&&I<Yt){Ot();return}const f=I<Yt&&be&&p.length>0;be&&p.length>0&&(C+=d.pulseSpeed);const k=be&&!f?new Set(p):null,B=we("--canvas-edge"),D=we("--canvas-edge-highlight"),H=we("--canvas-edge-dim"),z=we("--canvas-edge-label"),O=we("--canvas-edge-label-highlight"),J=we("--canvas-edge-label-dim"),Q=we("--canvas-arrow"),re=we("--canvas-arrow-highlight"),fe=we("--canvas-node-label"),ke=we("--canvas-node-label-dim"),Se=we("--canvas-type-badge"),Te=we("--canvas-type-badge-dim"),Be=we("--canvas-selection-border"),je=we("--canvas-node-border");if(n.save(),n.setTransform(g,0,0,g,0,0),n.clearRect(0,0,o.clientWidth,o.clientHeight),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),_&&i.scale>=m.smallNodes){const ee=new Map;for(const Pe of c.nodes){if(F!==null&&!F.has(Pe.id))continue;const Oe=ee.get(Pe.type)??[];Oe.push(Pe),ee.set(Pe.type,Oe)}for(const[Pe,Oe]of ee){if(Oe.length<2)continue;const st=Ae(Pe),nt=Ue*2.5;let He=1/0,qe=1/0,Fe=-1/0,Ke=-1/0;for(const We of Oe)We.x<He&&(He=We.x),We.y<qe&&(qe=We.y),We.x>Fe&&(Fe=We.x),We.y>Ke&&(Ke=We.y);n.beginPath();const oe=(Fe-He)/2+nt,Ie=(Ke-qe)/2+nt,Ne=(He+Fe)/2,ze=(qe+Ke)/2;n.ellipse(Ne,ze,oe,Ie,0,0,Math.PI*2),n.fillStyle=st,n.globalAlpha=.05,n.fill(),n.strokeStyle=st,n.globalAlpha=.12,n.lineWidth=1,n.setLineDash([4,4]),n.stroke(),n.setLineDash([]),n.globalAlpha=1}}let Ye=null;if(x.size>0){Ye=new Set;for(const ee of c.edges)x.has(ee.sourceId)&&Ye.add(ee.targetId),x.has(ee.targetId)&&Ye.add(ee.sourceId)}const tt=we("--accent")||"#d4a27f",_e=we("--canvas-walk-edge")||"#1a1a1a",it=i.scale>=m.hideArrows,Mt=V&&i.scale>=m.hideEdgeLabels;if(W){const ee=[],Pe=[],Oe=[],st=[],nt=[],He=[];for(const oe of c.edges){const Ie=c.nodeMap.get(oe.sourceId),Ne=c.nodeMap.get(oe.targetId);if(!Ie||!Ne||!Rt(Ie.x,Ie.y,i,o.clientWidth,o.clientHeight,200)&&!Rt(Ne.x,Ne.y,i,o.clientWidth,o.clientHeight,200))continue;const ze=F===null||F.has(oe.sourceId),We=F===null||F.has(oe.targetId),rn=ze&&We;if(F!==null&&!ze&&!We)continue;const jt=x.size>0&&(x.has(oe.sourceId)||x.has(oe.targetId))||F!==null&&rn,dn=F!==null&&!rn,pn=k!==null&&k.has(oe.sourceId)&&k.has(oe.targetId),un=ge?te==null?void 0:te.edges.find(Tt=>Tt.sourceId===oe.sourceId&&Tt.targetId===oe.targetId||Tt.targetId===oe.sourceId&&Tt.sourceId===oe.targetId):null,mn=!!(ge&&un&&ge.edgeIds.has(un.id));if(oe.sourceId===oe.targetId){St(Ie,oe.type,jt,B,D,z,O);continue}(mn?nt:pn?st:jt?Pe:dn?Oe:ee).push(Ie.x,Ie.y,Ne.x,Ne.y),(it||Mt)&&He.push({sx:Ie.x,sy:Ie.y,tx:Ne.x,ty:Ne.y,type:oe.type,highlighted:jt,edgeDimmed:dn,isPathEdge:mn,isWalkEdge:pn})}const qe=it?1.5:1,Ke=[{lines:ee,color:B,width:qe,alpha:1},{lines:Oe,color:H,width:qe,alpha:1},{lines:Pe,color:D,width:it?2.5:1,alpha:1},{lines:nt,color:tt,width:3,alpha:1},{lines:st,color:_e,width:3,alpha:.5+.5*Math.sin(C)}];for(const oe of Ke)if(oe.lines.length!==0){n.beginPath();for(let Ie=0;Ie<oe.lines.length;Ie+=4)n.moveTo(oe.lines[Ie],oe.lines[Ie+1]),n.lineTo(oe.lines[Ie+2],oe.lines[Ie+3]);n.strokeStyle=oe.color,n.lineWidth=oe.width,n.globalAlpha=oe.alpha,n.stroke()}n.globalAlpha=1;for(const oe of He)if(it&&ut(oe.sx,oe.sy,oe.tx,oe.ty,oe.highlighted||oe.isPathEdge,Q,re),Mt){const Ie=(oe.sx+oe.tx)/2,Ne=(oe.sy+oe.ty)/2;n.fillStyle=oe.highlighted?O:oe.edgeDimmed?J:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.textBaseline="bottom",n.fillText(oe.type,Ie,Ne-4)}}const Ut=performance.now()-E,Le=Math.min(1,Ut/u),Ve=1-(1-Le)*(1-Le),Je=Le<1,cn=i.scale<m.hullsOnly,Vn=!cn&&i.scale<m.dotNodes;if(!cn)for(const ee of c.nodes){if(!Rt(ee.x,ee.y,i,o.clientWidth,o.clientHeight))continue;const Pe=Ae(ee.type);if(Vn){const Ne=F!==null&&!F.has(ee.id);n.fillStyle=Pe;const ze=Ne?.1:.8;n.globalAlpha=Je?ze*Ve:ze,n.fillRect(ee.x-2,ee.y-2,4,4);continue}const Oe=x.has(ee.id),st=Ye!==null&&Ye.has(ee.id),nt=F!==null&&!F.has(ee.id),He=nt||x.size>0&&!Oe&&!st,qe=i.scale<m.smallNodes?Ue*.5:Ue,Fe=Je?qe*Ve:qe;if(k!=null&&k.has(ee.id)){const Ne=p[p.length-1]===ee.id,ze=.5+.5*Math.sin(C),We=we("--accent")||"#d4a27f";n.save(),n.strokeStyle=We,n.lineWidth=Ne?3:2,n.globalAlpha=Ne?.5+.5*ze:.3+.4*ze,n.beginPath(),n.arc(ee.x,ee.y,Fe+(Ne?6:4),0,Math.PI*2),n.stroke(),n.restore()}Oe&&(n.save(),n.shadowColor=Pe,n.shadowBlur=20,n.beginPath(),n.arc(ee.x,ee.y,Fe+3,0,Math.PI*2),n.fillStyle=Pe,n.globalAlpha=.3,n.fill(),n.restore()),n.beginPath(),n.arc(ee.x,ee.y,Fe,0,Math.PI*2),n.fillStyle=Pe;const Ke=nt?.1:He?.3:1;n.globalAlpha=Je?Ke*Ve:Ke,n.fill(),n.strokeStyle=Oe?Be:je,n.lineWidth=Oe?3:1.5,n.stroke(),n.globalAlpha=1,ee.pinned&&(n.save(),n.strokeStyle=je,n.globalAlpha=.55,n.lineWidth=1,n.setLineDash([3,3]),n.beginPath(),n.arc(ee.x,ee.y,Fe+4,0,Math.PI*2),n.stroke(),n.setLineDash([]),n.restore()),ge&&ge.nodeIds.has(ee.id)&&!Oe&&(n.save(),n.shadowColor=we("--accent")||"#d4a27f",n.shadowBlur=15,n.beginPath(),n.arc(ee.x,ee.y,Fe+2,0,Math.PI*2),n.strokeStyle=we("--accent")||"#d4a27f",n.globalAlpha=.5,n.lineWidth=2,n.stroke(),n.restore());const oe=te==null?void 0:te.nodes.find(Ne=>Ne.id===ee.id);if(((ln=oe==null?void 0:oe.properties)==null?void 0:ln._starred)===!0&&(n.fillStyle="#ffd700",n.font="10px system-ui, sans-serif",n.textAlign="left",n.textBaseline="bottom",n.fillText("★",ee.x+Fe-2,ee.y-Fe+2)),i.scale>=m.hideLabels){const Ne=ee.label.length>24?ee.label.slice(0,22)+"...":ee.label,ze=He?ke:fe;An(n,Ne,ee.x,ee.y+Fe+4,"11px system-ui, sans-serif",ze,"top")}if(i.scale>=m.hideBadges){const Ne=He?Te:Se;An(n,ee.type,ee.x,ee.y-Fe-3,"9px system-ui, sans-serif",Ne,"bottom")}n.globalAlpha=1}if(n.restore(),n.restore(),f){const ee=o.width,Pe=o.height;(!P||P.width!==ee||P.height!==Pe)&&(P=new OffscreenCanvas(ee,Pe),$=P.getContext("2d")),$&&($.clearRect(0,0,ee,Pe),$.drawImage(o,0,0),K=!1),Ot();return}X&&c.nodes.length>1&&Wt(),U&&(n.save(),n.setTransform(g,0,0,g,0,0),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),ct(),n.restore())}function Wt(){if(!c)return;const f=140,k=100,B=8,D=o.clientWidth-f-16,H=o.clientHeight-k-16;let z=1/0,O=1/0,J=-1/0,Q=-1/0;for(const Le of c.nodes)Le.x<z&&(z=Le.x),Le.y<O&&(O=Le.y),Le.x>J&&(J=Le.x),Le.y>Q&&(Q=Le.y);const re=J-z||1,fe=Q-O||1,ke=Math.min((f-B*2)/re,(k-B*2)/fe),Se=D+B+(f-B*2-re*ke)/2,Te=H+B+(k-B*2-fe*ke)/2;n.save(),n.setTransform(g,0,0,g,0,0),n.fillStyle=we("--bg-surface")||"#1a1a1a",n.globalAlpha=.85,n.beginPath(),n.roundRect(D,H,f,k,8),n.fill(),n.strokeStyle=we("--border")||"#2a2a2a",n.globalAlpha=1,n.lineWidth=1,n.stroke(),n.globalAlpha=.15,n.strokeStyle=we("--canvas-edge")||"#555",n.lineWidth=.5;for(const Le of c.edges){const Ve=c.nodeMap.get(Le.sourceId),Je=c.nodeMap.get(Le.targetId);!Ve||!Je||Le.sourceId===Le.targetId||(n.beginPath(),n.moveTo(Se+(Ve.x-z)*ke,Te+(Ve.y-O)*ke),n.lineTo(Se+(Je.x-z)*ke,Te+(Je.y-O)*ke),n.stroke())}n.globalAlpha=.8;for(const Le of c.nodes){const Ve=Se+(Le.x-z)*ke,Je=Te+(Le.y-O)*ke;n.beginPath(),n.arc(Ve,Je,2,0,Math.PI*2),n.fillStyle=Ae(Le.type),n.fill()}const Be=i.x,je=i.y,Ye=i.x+o.clientWidth/i.scale,tt=i.y+o.clientHeight/i.scale,_e=Se+(Be-z)*ke,it=Te+(je-O)*ke,Mt=(Ye-Be)*ke,Ut=(tt-je)*ke;n.globalAlpha=.3,n.strokeStyle=we("--accent")||"#d4a27f",n.lineWidth=1.5,n.strokeRect(Math.max(D,Math.min(_e,D+f)),Math.max(H,Math.min(it,H+k)),Math.min(Mt,f),Math.min(Ut,k)),n.globalAlpha=1,n.restore()}function ut(f,k,B,D,H,z,O){const J=Math.atan2(D-k,B-f),Q=B-Math.cos(J)*Ue,re=D-Math.sin(J)*Ue,fe=8;n.beginPath(),n.moveTo(Q,re),n.lineTo(Q-fe*Math.cos(J-.4),re-fe*Math.sin(J-.4)),n.lineTo(Q-fe*Math.cos(J+.4),re-fe*Math.sin(J+.4)),n.closePath(),n.fillStyle=H?O:z,n.fill()}function St(f,k,B,D,H,z,O){const J=f.x+Ue+15,Q=f.y-Ue-15;n.beginPath(),n.arc(J,Q,15,0,Math.PI*2),n.strokeStyle=B?H:D,n.lineWidth=B?2.5:1.5,n.stroke(),V&&(n.fillStyle=B?O:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.fillText(k,J,Q-18))}function mt(){if(!ce||!ue)return;const f=performance.now()-ue.time,k=Math.min(f/ve,1),B=1-Math.pow(1-k,3);i.x=ue.x+(ce.x-ue.x)*B,i.y=ue.y+(ce.y-ue.y)*B,ae(),Xe(),k<1?requestAnimationFrame(mt):(ce=null,ue=null)}let a=0;function v(){if(!be||p.length===0){a=0;return}Xe(),a=requestAnimationFrame(v)}function R(){if(!c||c.nodes.length===0)return;let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const re of c.nodes)re.x<f&&(f=re.x),re.y<k&&(k=re.y),re.x>B&&(B=re.x),re.y>D&&(D=re.y);const H=Ue*4,z=B-f+H*2,O=D-k+H*2,J=o.clientWidth/Math.max(z,1),Q=o.clientHeight/Math.max(O,1);i.scale=Math.min(J,Q,2),i.x=(f+B)/2-o.clientWidth/(2*i.scale),i.y=(k+D)/2-o.clientHeight/(2*i.scale),h()}function j(){if(!c||I<Yt){M=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(v));return}I=So(c,I),b.rebuild(c.nodes),Xe(),M=requestAnimationFrame(j)}let ne=!1,de=0,le=0,he=0,Me=0;o.addEventListener("mousedown",f=>{Y="pending",ne=!1,de=f.clientX,le=f.clientY,he=f.clientX,Me=f.clientY;const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D);if(H&&!be){if(Z=[],x.has(H.id)&&x.size>1)for(const J of x){const Q=c==null?void 0:c.nodeMap.get(J);Q&&Z.push({node:Q,startX:Q.x,startY:Q.y})}else Z.push({node:H,startX:H.x,startY:H.y});const[z,O]=Re(B,D);q=z,me=O}else if(!H&&f.shiftKey){const[z,O]=Re(B,D);U={x1:z,y1:O,x2:z,y2:O}}}),o.addEventListener("mousemove",f=>{if(Y==="idle")return;const k=f.clientX-de,B=f.clientY-le,D=Math.abs(f.clientX-he),H=Math.abs(f.clientY-Me);if(Y==="pending"&&(D>Ee||H>Ee)&&(ne=!0,Z.length>0?(Y="nodeDrag",N&&w&&w.postMessage({type:"stop"})):U?Y="rubberBand":Y="pan"),Y==="nodeDrag"){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Q,re]=Re(O,J),fe=Q-q,ke=re-me;for(const Se of Z)Se.node.x=Se.startX+fe,Se.node.y=Se.startY+ke,Se.node.vx=0,Se.node.vy=0,Se.node.pinned=!0,pe.add(Se.node.id);b.rebuild((c==null?void 0:c.nodes)??[]),h()}else if(Y==="rubberBand"&&U){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Q,re]=Re(O,J);U.x2=Q,U.y2=re,h()}else Y==="pan"&&(i.x-=k/i.scale,i.y-=B/i.scale,h());de=f.clientX,le=f.clientY}),o.addEventListener("mouseup",f=>{const k=Y==="nodeDrag",B=Y==="rubberBand";if(Z.map(Q=>Q.node.id),k){if(N&&w&&c){const Q=Z.map(re=>({id:re.node.id,x:re.node.x,y:re.node.y}));w.postMessage({type:"pin",updates:Q}),w.postMessage({type:"resume",alpha:.5})}else I=Math.max(I,.5),M||j();Y="idle",Z=[],h();return}if(B&&U&&c){const Q=Math.min(U.x1,U.x2),re=Math.max(U.x1,U.x2),fe=Math.min(U.y1,U.y2),ke=Math.max(U.y1,U.y2);f.shiftKey||x.clear();for(const Te of c.nodes)Te.x>=Q&&Te.x<=re&&Te.y>=fe&&Te.y<=ke&&x.add(Te.id);const Se=[...x];e==null||e(Se.length>0?Se:null),U=null,Y="idle",h();return}if(Y==="pan"){Y="idle";return}if(Y="idle",U=null,ne)return;const D=o.getBoundingClientRect(),H=f.clientX-D.left,z=f.clientY-D.top,O=et(H,z),J=f.ctrlKey||f.metaKey||f.shiftKey;if(be&&G&&O&&c){const Q=p.length>0?p[p.length-1]:G[0],re=new Set([Q]),fe=[{id:Q,path:[Q]}];let ke=null;for(;fe.length>0;){const{id:je,path:Ye}=fe.shift();if(je===O.id){ke=Ye;break}for(const tt of c.edges){let _e=null;tt.sourceId===je?_e=tt.targetId:tt.targetId===je&&(_e=tt.sourceId),_e&&!re.has(_e)&&(re.add(_e),fe.push({id:_e,path:[...Ye,_e]}))}}if(!ke)return;for(const je of ke.slice(1))p.includes(je)||p.push(je);G=[O.id];const Se=Math.max(1,ye);ye=Se;const Te=Ln(te,[O.id],Se);cancelAnimationFrame(M),w&&w.postMessage({type:"stop"}),c=Ht(Te),b.rebuild(c.nodes),I=1,x=new Set([O.id]),F=null,i={x:0,y:0,scale:1},N=Te.nodes.length>=T;const Be=N?L():null;Be?Be.postMessage({type:"start",data:Te}):(N=!1,j()),setTimeout(()=>{c&&R()},300),s==null||s({seedNodeIds:[O.id],hops:Se,totalNodes:Te.nodes.length}),e==null||e([O.id]);return}if(O){J?x.has(O.id)?x.delete(O.id):x.add(O.id):x.size===1&&x.has(O.id)?x.clear():(x.clear(),x.add(O.id));const Q=[...x];e==null||e(Q.length>0?Q:null)}else x.clear(),e==null||e(null);h()}),o.addEventListener("mouseleave",()=>{if(Y==="nodeDrag")if(N&&w&&Z.length>0){const f=Z.map(k=>({id:k.node.id,x:k.node.x,y:k.node.y}));w.postMessage({type:"pin",updates:f}),w.postMessage({type:"resume",alpha:.5})}else I=Math.max(I,.5),M||j();Y==="rubberBand"&&(U=null,h()),Y="idle",Z=[]}),o.addEventListener("wheel",f=>{f.preventDefault();const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,[H,z]=Re(B,D),O=f.ctrlKey?1-f.deltaY*.01:f.deltaY>0?.9:1.1;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*O)),i.x=H-B/i.scale,i.y=z-D/i.scale,h()},{passive:!1});let xe=[],Ge=0,Nt=1,ht=0,Lt=0,ft=!1;o.addEventListener("touchstart",f=>{f.preventDefault(),xe=Array.from(f.touches),xe.length===2?(Ge=an(xe[0],xe[1]),Nt=i.scale):xe.length===1&&(de=xe[0].clientX,le=xe[0].clientY,ht=xe[0].clientX,Lt=xe[0].clientY,ft=!1)},{passive:!1}),o.addEventListener("touchmove",f=>{f.preventDefault();const k=Array.from(f.touches);if(k.length===2&&xe.length===2){const D=an(k[0],k[1])/Ge;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,Nt*D)),h()}else if(k.length===1){const B=k[0].clientX-de,D=k[0].clientY-le;(Math.abs(k[0].clientX-ht)>10||Math.abs(k[0].clientY-Lt)>10)&&(ft=!0),i.x-=B/i.scale,i.y-=D/i.scale,de=k[0].clientX,le=k[0].clientY,h()}xe=k},{passive:!1}),o.addEventListener("touchend",f=>{if(f.preventDefault(),ft||f.changedTouches.length!==1)return;const k=f.changedTouches[0],B=o.getBoundingClientRect(),D=k.clientX-B.left,H=k.clientY-B.top,z=et(D,H);if(z){x.size===1&&x.has(z.id)?x.clear():(x.clear(),x.add(z.id));const O=[...x];e==null||e(O.length>0?O:null)}else x.clear(),e==null||e(null);h()},{passive:!1}),o.addEventListener("gesturestart",f=>f.preventDefault()),o.addEventListener("gesturechange",f=>f.preventDefault());function an(f,k){const B=f.clientX-k.clientX,D=f.clientY-k.clientY;return Math.sqrt(B*B+D*D)}const gt=document.createElement("div");gt.className="zoom-controls";const yt=document.createElement("button");yt.className="zoom-btn",yt.textContent="+",yt.title="Zoom in",yt.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.min(r.zoomMax,i.scale*r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const Ct=document.createElement("button");Ct.className="zoom-btn",Ct.textContent="−",Ct.title="Zoom out",Ct.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.max(r.zoomMin,i.scale/r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const bt=document.createElement("button");bt.className="zoom-btn",bt.textContent="○",bt.title="Reset zoom",bt.addEventListener("click",()=>{if(c){if(i={x:0,y:0,scale:1},c.nodes.length>0){let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const O of c.nodes)O.x<f&&(f=O.x),O.y<k&&(k=O.y),O.x>B&&(B=O.x),O.y>D&&(D=O.y);const H=(f+B)/2,z=(k+D)/2;i.x=H-o.clientWidth/2,i.y=z-o.clientHeight/2}h()}}),gt.appendChild(yt),gt.appendChild(bt),gt.appendChild(Ct),t.appendChild(gt);const De=document.createElement("div");De.className="node-tooltip",De.style.display="none",t.appendChild(De);let It=null,ot=null;return o.addEventListener("mousemove",f=>{if(Y!=="idle"&&Y!=="pending"){De.style.display!=="none"&&(De.style.display="none",It=null);return}const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D),z=(H==null?void 0:H.id)??null;z!==It?(It=z,De.style.display="none",ot&&clearTimeout(ot),ot=null,z&&H&&(ot=setTimeout(()=>{if(!c||!te)return;const O=c.edges.filter(J=>J.sourceId===z||J.targetId===z).length;De.textContent=`${H.label} · ${H.type} · ${O} edge${O!==1?"s":""}`,De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`,De.style.display="block"},200))):z&&De.style.display==="block"&&(De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`)}),o.addEventListener("mouseleave",()=>{De.style.display="none",It=null,ot&&clearTimeout(ot),ot=null}),{loadGraph(f){if(cancelAnimationFrame(M),w&&w.postMessage({type:"stop"}),Ao(),te=f,G=null,Ce=null,se=null,E=performance.now(),c=Ht(f),b.rebuild(c.nodes),I=1,x=new Set,F=null,pe.clear(),Y="idle",Z=[],U=null,i={x:0,y:0,scale:1},c.nodes.length>0){let B=1/0,D=1/0,H=-1/0,z=-1/0;for(const fe of c.nodes)fe.x<B&&(B=fe.x),fe.y<D&&(D=fe.y),fe.x>H&&(H=fe.x),fe.y>z&&(z=fe.y);const O=(B+H)/2,J=(D+z)/2,Q=o.clientWidth,re=o.clientHeight;i.x=O-Q/2,i.y=J-re/2}N=f.nodes.length>=T;const k=N?L():null;k?k.postMessage({type:"start",data:f}):(N=!1,j())},setFilteredNodeIds(f){F=f,h()},releaseAllPins(){if(!c)return!1;let f=!1;for(const k of c.nodes)k.pinned&&(f=!0,k.pinned=!1);return pe.clear(),Y="idle",Z=[],U=null,f&&(N&&w?w.postMessage({type:"unpin",ids:"all"}):(I=Math.max(I,.5),M||j()),h()),f},hasPinnedNodes(){if(!c)return!1;for(const f of c.nodes)if(f.pinned)return!0;return!1},clearSelection(){x.size!==0&&(x.clear(),e==null||e(null),h())},getSelectedNodeIds(){return[...x]},panToNode(f){this.panToNodes([f])},panToNodes(f){if(!c||f.length===0)return;const k=f.map(H=>c.nodeMap.get(H)).filter(Boolean);if(k.length===0)return;x=new Set(f),e==null||e(f);const B=o.clientWidth,D=o.clientHeight;if(k.length===1)ue={x:i.x,y:i.y,time:performance.now()},ce={x:k[0].x-B/(2*i.scale),y:k[0].y-D/(2*i.scale)};else{let H=1/0,z=1/0,O=-1/0,J=-1/0;for(const Be of k)Be.x<H&&(H=Be.x),Be.y<z&&(z=Be.y),Be.x>O&&(O=Be.x),Be.y>J&&(J=Be.y);const Q=Ue*4,re=O-H+Q*2,fe=J-z+Q*2,ke=Math.min(B/re,D/fe,i.scale);i.scale=ke;const Se=(H+O)/2,Te=(z+J)/2;ue={x:i.x,y:i.y,time:performance.now()},ce={x:Se-B/(2*i.scale),y:Te-D/(2*i.scale)}}mt()},setEdges(f){W=f,h()},setEdgeLabels(f){V=f,h()},setTypeHulls(f){_=f,h()},setMinimap(f){X=f,h()},centerView(){R()},panBy(f,k){i.x+=f/i.scale,i.y+=k/i.scale,h()},zoomBy(f){const k=o.clientWidth/2,B=o.clientHeight/2,[D,H]=Re(k,B);i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*f)),i.x=D-k/i.scale,i.y=H-B/i.scale,h()},reheat(){N&&w?w.postMessage({type:"params",params:wt()}):(I=.5,cancelAnimationFrame(M),j())},exportImage(f){if(!c)return"";const k=o.width,B=o.height;if(f==="png"){const O=document.createElement("canvas");O.width=k,O.height=B;const J=O.getContext("2d");return J.fillStyle=we("--bg")||"#141414",J.fillRect(0,0,k,B),J.drawImage(o,0,0),Gn(J,k,B),O.toDataURL("image/png")}const D=o.toDataURL("image/png"),H=Math.max(16,Math.round(k/80)),z=`<svg xmlns="http://www.w3.org/2000/svg" width="${k}" height="${B}">
|
|
3
|
+
<image href="${D}" width="${k}" height="${B}"/>
|
|
4
|
+
<text x="${k-20}" y="${B-16}" text-anchor="end" font-family="system-ui, sans-serif" font-size="${H}" fill="#ffffff" opacity="0.4">backpackontology.com</text>
|
|
5
|
+
</svg>`;return"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(z)},enterFocus(f,k){if(!te||!c)return;for(const H of c.nodes)H.pinned=!1;pe.clear(),Y="idle",Z=[],U=null,G||(Ce=c,se={...i}),G=f,ye=k;const B=Ln(te,f,k);cancelAnimationFrame(M),w&&w.postMessage({type:"stop"}),c=Ht(B),b.rebuild(c.nodes),I=1,x=new Set(f),F=null,i={x:0,y:0,scale:1},N=B.nodes.length>=T;const D=N?L():null;D?D.postMessage({type:"start",data:B}):(N=!1,j()),setTimeout(()=>{!c||!G||R()},300),s==null||s({seedNodeIds:f,hops:k,totalNodes:B.nodes.length})},exitFocus(){if(!(!G||!Ce)){cancelAnimationFrame(M),w&&w.postMessage({type:"stop"}),c=Ce;for(const f of c.nodes)f.pinned=!1;pe.clear(),Y="idle",Z=[],U=null,b.rebuild(c.nodes),i=se??{x:0,y:0,scale:1},G=null,Ce=null,se=null,x=new Set,F=null,h(),s==null||s(null)}},isFocused(){return G!==null},getFocusInfo(){return!G||!c?null:{seedNodeIds:G,hops:ye,totalNodes:c.nodes.length}},findPath(f,k){if(!c)return null;const B=new Set([f]),D=[{nodeId:f,path:[f],edges:[]}];for(;D.length>0;){const{nodeId:H,path:z,edges:O}=D.shift();if(H===k)return{nodeIds:z,edgeIds:O};for(const J of c.edges){let Q=null;if(J.sourceId===H?Q=J.targetId:J.targetId===H&&(Q=J.sourceId),Q&&!B.has(Q)){B.add(Q);const re=te==null?void 0:te.edges.find(fe=>fe.sourceId===J.sourceId&&fe.targetId===J.targetId||fe.targetId===J.sourceId&&fe.sourceId===J.targetId);D.push({nodeId:Q,path:[...z,Q],edges:[...O,(re==null?void 0:re.id)??""]})}}}return null},setHighlightedPath(f,k){f&&k?ge={nodeIds:new Set(f),edgeIds:new Set(k)}:ge=null,h()},clearHighlightedPath(){ge=null,h()},setWalkMode(f){be=f,this.releaseAllPins(),f?(p=G?[...G]:[...x],a||(a=requestAnimationFrame(v))):(p=[],a&&(cancelAnimationFrame(a),a=0)),h()},getWalkMode(){return be},getWalkTrail(){return[...p]},getFilteredNodeIds(){return F},removeFromWalkTrail(f){p=p.filter(k=>k!==f),h()},nodeAtScreen(f,k){return et(f,k)},getNodeIds(){if(!c)return[];if(G){const f=new Set(G),k=c.nodes.filter(D=>f.has(D.id)).map(D=>D.id),B=c.nodes.filter(D=>!f.has(D.id)).map(D=>D.id);return[...k,...B]}return c.nodes.map(f=>f.id)},destroy(){cancelAnimationFrame(M),S&&(cancelAnimationFrame(S),S=0),a&&(cancelAnimationFrame(a),a=0),w&&(w.terminate(),w=null),P=null,$=null,Qe.disconnect()}};function Gn(f,k,B){const D=Math.max(16,Math.round(k/80));f.save(),f.font=`${D}px system-ui, sans-serif`,f.fillStyle="rgba(255, 255, 255, 0.4)",f.textAlign="right",f.textBaseline="bottom",f.fillText("backpackontology.com",k-20,B-16),f.restore()}}function rt(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}const $o="✎";function Fo(t,e,s,l,m){const r=document.createElement("div");r.className="info-panel-content";let d=[],o=-1,n=!1,g=null,i=[],c=!1,I=[],M=-1;const x=e.mount("info",r,{title:"Node info",persistKey:"info-panel",hideOnClose:!0,onClose:()=>{d=[],o=-1}});x.setVisible(!1);function F(){x.setVisible(!1),d=[],o=-1}function W(q){!g||!l||(o<d.length-1&&(d=d.slice(0,o+1)),d.push(q),o=d.length-1,n=!0,l(q),n=!1)}function V(){if(o<=0||!g)return;o--,n=!0;const q=d[o];l==null||l(q),Y(q,g),n=!1}function _(){if(o>=d.length-1||!g)return;o++,n=!0;const q=d[o];l==null||l(q),Y(q,g),n=!1}function X(){const q=[{label:"Back",iconText:"←",onClick:V,disabled:o<=0},{label:"Forward",iconText:"→",onClick:_,disabled:o>=d.length-1}];m&&i.length>0&&q.push({label:"Focus",iconText:"◎",onClick:()=>{c||m(i)},disabled:c}),x.setHeaderButtons(q)}function Y(q,me){const U=me.nodes.find(h=>h.id===q);if(!U)return;const pe=me.edges.filter(h=>h.sourceId===q||h.targetId===q);I=pe.map(h=>h.sourceId===q?h.targetId:h.sourceId),M=-1,r.replaceChildren(),x.setTitle(rt(U)),X(),x.setVisible(!0);const Ee=document.createElement("div");Ee.className="info-panel-header";const te=document.createElement("div");te.className="info-header";const G=document.createElement("span");if(G.className="info-type-badge",G.textContent=U.type,G.style.backgroundColor=Ae(U.type),s){G.classList.add("info-editable");const h=document.createElement("button");h.className="info-inline-edit",h.textContent=$o,h.addEventListener("click",T=>{T.stopPropagation();const w=document.createElement("input");w.type="text",w.className="info-edit-inline-input",w.value=U.type,G.textContent="",G.appendChild(w),w.focus(),w.select();const N=()=>{const L=w.value.trim();L&&L!==U.type?s.onChangeNodeType(q,L):(G.textContent=U.type,G.appendChild(h))};w.addEventListener("blur",N),w.addEventListener("keydown",L=>{L.key==="Enter"&&w.blur(),L.key==="Escape"&&(w.value=U.type,w.blur())})}),G.appendChild(h)}const ye=document.createElement("h3");ye.className="info-label",ye.textContent=rt(U);const Ce=document.createElement("span");Ce.className="info-id",Ce.textContent=U.id,te.appendChild(G),te.appendChild(ye),te.appendChild(Ce),Ee.appendChild(te),r.appendChild(Ee);const se=document.createElement("div");se.className="info-panel-body";const ge=Object.keys(U.properties),be=Et("Properties");if(ge.length>0){const h=document.createElement("dl");h.className="info-props";for(const T of ge){const w=document.createElement("dt");w.textContent=T;const N=document.createElement("dd");if(s){const L=qt(U.properties[T]),y=document.createElement("textarea");y.className="info-edit-input",y.value=L,y.rows=1,y.addEventListener("input",()=>Pn(y)),y.addEventListener("keydown",$=>{$.key==="Enter"&&!$.shiftKey&&($.preventDefault(),y.blur())}),y.addEventListener("blur",()=>{const $=y.value;$!==L&&s.onUpdateNode(q,{[T]:Oo($)})}),N.appendChild(y),requestAnimationFrame(()=>Pn(y));const P=document.createElement("button");P.className="info-delete-prop",P.textContent="×",P.title=`Remove ${T}`,P.addEventListener("click",()=>{const $={...U.properties};delete $[T],s.onUpdateNode(q,$)}),N.appendChild(P)}else N.appendChild(Do(U.properties[T]));h.appendChild(w),h.appendChild(N)}be.appendChild(h)}if(s){const h=document.createElement("button");h.className="info-add-btn",h.textContent="+ Add property",h.addEventListener("click",()=>{const T=document.createElement("div");T.className="info-add-row";const w=document.createElement("input");w.type="text",w.className="info-edit-input",w.placeholder="key";const N=document.createElement("input");N.type="text",N.className="info-edit-input",N.placeholder="value";const L=document.createElement("button");L.className="info-add-save",L.textContent="Add",L.addEventListener("click",()=>{w.value&&s.onAddProperty(q,w.value,N.value)}),T.appendChild(w),T.appendChild(N),T.appendChild(L),be.appendChild(T),w.focus()}),be.appendChild(h)}if(se.appendChild(be),pe.length>0){const h=Et(`Connections (${pe.length})`),T=document.createElement("ul");T.className="info-connections";for(const w of pe){const N=w.sourceId===q,L=N?w.targetId:w.sourceId,y=me.nodes.find(ve=>ve.id===L),P=y?rt(y):L,$=document.createElement("li");if($.className="info-connection",l&&y&&($.classList.add("info-connection-link"),$.addEventListener("click",ve=>{ve.target.closest(".info-delete-edge")||W(L)})),y){const ve=document.createElement("span");ve.className="info-target-dot",ve.style.backgroundColor=Ae(y.type),$.appendChild(ve)}const K=document.createElement("span");K.className="info-arrow",K.textContent=N?"→":"←";const ae=document.createElement("span");ae.className="info-edge-type",ae.textContent=w.type;const ce=document.createElement("span");ce.className="info-target",ce.textContent=P,$.appendChild(K),$.appendChild(ae),$.appendChild(ce);const ue=Object.keys(w.properties);if(ue.length>0){const ve=document.createElement("div");ve.className="info-edge-props";for(const $e of ue){const Qe=document.createElement("span");Qe.className="info-edge-prop",Qe.textContent=`${$e}: ${qt(w.properties[$e])}`,ve.appendChild(Qe)}$.appendChild(ve)}if(s){const ve=document.createElement("button");ve.className="info-delete-edge",ve.textContent="×",ve.title="Remove connection",ve.addEventListener("click",$e=>{$e.stopPropagation(),s.onDeleteEdge(w.id)}),$.appendChild(ve)}T.appendChild($)}h.appendChild(T),se.appendChild(h)}const p=Et("Timestamps"),C=document.createElement("dl");C.className="info-props";const E=document.createElement("dt");E.textContent="created";const u=document.createElement("dd");u.textContent=Rn(U.createdAt);const b=document.createElement("dt");b.textContent="updated";const S=document.createElement("dd");if(S.textContent=Rn(U.updatedAt),C.appendChild(E),C.appendChild(u),C.appendChild(b),C.appendChild(S),p.appendChild(C),se.appendChild(p),s){const h=document.createElement("div");h.className="info-section info-danger";const T=document.createElement("button");T.className="info-delete-node",T.textContent="Delete node",T.addEventListener("click",()=>{s.onDeleteNode(q),F()}),h.appendChild(T),se.appendChild(h)}r.appendChild(se)}function Z(q,me){const U=new Set(q),pe=me.nodes.filter(p=>U.has(p.id));if(pe.length===0)return;const Ee=me.edges.filter(p=>U.has(p.sourceId)&&U.has(p.targetId));r.replaceChildren(),x.setTitle(`${pe.length} nodes selected`),X(),x.setVisible(!0);const te=document.createElement("div");te.className="info-header";const G=document.createElement("h3");G.className="info-label",G.textContent=`${pe.length} nodes selected`,te.appendChild(G);const ye=document.createElement("div");ye.className="info-badge-row";const Ce=new Map;for(const p of pe)Ce.set(p.type,(Ce.get(p.type)??0)+1);for(const[p,C]of Ce){const E=document.createElement("span");E.className="info-type-badge",E.style.backgroundColor=Ae(p),E.textContent=C>1?`${p} (${C})`:p,ye.appendChild(E)}te.appendChild(ye),r.appendChild(te);const se=Et("Selected Nodes"),ge=document.createElement("ul");ge.className="info-connections";for(const p of pe){const C=document.createElement("li");C.className="info-connection",l&&(C.classList.add("info-connection-link"),C.addEventListener("click",()=>{W(p.id)}));const E=document.createElement("span");E.className="info-target-dot",E.style.backgroundColor=Ae(p.type);const u=document.createElement("span");u.className="info-target",u.textContent=rt(p);const b=document.createElement("span");b.className="info-edge-type",b.textContent=p.type,C.appendChild(E),C.appendChild(u),C.appendChild(b),ge.appendChild(C)}se.appendChild(ge),r.appendChild(se);const be=Et(Ee.length>0?`Connections Between Selected (${Ee.length})`:"Connections Between Selected");if(Ee.length===0){const p=document.createElement("p");p.className="info-empty-message",p.textContent="No direct connections between selected nodes",be.appendChild(p)}else{const p=document.createElement("ul");p.className="info-connections";for(const C of Ee){const E=me.nodes.find($=>$.id===C.sourceId),u=me.nodes.find($=>$.id===C.targetId),b=E?rt(E):C.sourceId,S=u?rt(u):C.targetId,h=document.createElement("li");if(h.className="info-connection",E){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(E.type),h.appendChild($)}const T=document.createElement("span");T.className="info-target",T.textContent=b;const w=document.createElement("span");w.className="info-arrow",w.textContent="→";const N=document.createElement("span");N.className="info-edge-type",N.textContent=C.type;const L=document.createElement("span");if(L.className="info-arrow",L.textContent="→",h.appendChild(T),h.appendChild(w),h.appendChild(N),h.appendChild(L),u){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(u.type),h.appendChild($)}const y=document.createElement("span");y.className="info-target",y.textContent=S,h.appendChild(y);const P=Object.keys(C.properties);if(P.length>0){const $=document.createElement("div");$.className="info-edge-props";for(const K of P){const ae=document.createElement("span");ae.className="info-edge-prop",ae.textContent=`${K}: ${qt(C.properties[K])}`,$.appendChild(ae)}h.appendChild($)}p.appendChild(h)}be.appendChild(p)}r.appendChild(be)}return{show(q,me){if(g=me,i=q,q.length===1&&!n){const U=q[0];d[o]!==U&&(o<d.length-1&&(d=d.slice(0,o+1)),d.push(U),o=d.length-1)}q.length===1?Y(q[0],me):q.length>1&&Z(q,me)},hide:F,goBack:V,goForward:_,cycleConnection(q){if(I.length===0)return null;M===-1?M=q===1?0:I.length-1:(M+=q,M>=I.length&&(M=0),M<0&&(M=I.length-1));const me=r.querySelectorAll(".info-connection");return me.forEach((U,pe)=>{U.classList.toggle("info-connection-active",pe===M)}),M>=0&&me[M]&&me[M].scrollIntoView({block:"nearest"}),I[M]??null},setFocusDisabled(q){c=q,X()},get visible(){return x.isVisible()}}}function Et(t){const e=document.createElement("div");e.className="info-section";const s=document.createElement("h4");return s.className="info-section-title",s.textContent=t,e.appendChild(s),e}function Do(t){if(Array.isArray(t)){const s=document.createElement("div");s.className="info-array";for(const l of t){const m=document.createElement("span");m.className="info-tag",m.textContent=String(l),s.appendChild(m)}return s}if(t!==null&&typeof t=="object"){const s=document.createElement("pre");return s.className="info-json",s.textContent=JSON.stringify(t,null,2),s}const e=document.createElement("span");return e.className="info-value",e.textContent=String(t??""),e}function qt(t){return Array.isArray(t)?t.map(String).join(", "):t!==null&&typeof t=="object"?JSON.stringify(t):String(t??"")}function Oo(t){const e=t.trim();if(e==="true")return!0;if(e==="false")return!1;if(e!==""&&!isNaN(Number(e)))return Number(e);if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{return t}return t}function Pn(t){t.style.height="auto",t.style.height=t.scrollHeight+"px"}function Rn(t){try{return new Date(t).toLocaleString()}catch{return t}}const en=30,Wo=39,Uo=45,Bn=380,jo=70,zo=16,$n=80,qn="backpack-viewer:panel:",_o="has-fullscreen-panel";let Bt=en;function dt(t){Bt++,Bt>Wo&&(document.querySelectorAll(".extension-panel").forEach(e=>{e.style.zIndex=String(en+1)}),Bt=en+2),t.style.zIndex=String(Bt)}let $t=0;function Ft(t,e){const s=t.id==="canvas-container"?t:t.closest("#canvas-container")??t;e?$t++:$t=Math.max(0,$t-1),s.classList.toggle(_o,$t>0)}function Xt(t){try{const e=localStorage.getItem(qn+t);if(!e)return null;const s=JSON.parse(e);if(s&&typeof s=="object")return s}catch{}return null}function Fn(t,e){try{localStorage.setItem(qn+t,JSON.stringify(e))}catch{}}function Dn(){return at({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"4 9 4 4 9 4"}},{tag:"polyline",attrs:{points:"20 9 20 4 15 4"}},{tag:"polyline",attrs:{points:"4 15 4 20 9 20"}},{tag:"polyline",attrs:{points:"20 15 20 20 15 20"}}])}function Ho(){return at({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"9 4 9 9 4 9"}},{tag:"polyline",attrs:{points:"15 4 15 9 20 9"}},{tag:"polyline",attrs:{points:"9 20 9 15 4 15"}},{tag:"polyline",attrs:{points:"15 20 15 15 20 15"}}])}function Yo(t){const e=document.createElement("div");e.className="extension-panel-layer",t.appendChild(e);function s(){const r=t.getBoundingClientRect();return{left:Math.max(0,r.width-Bn-zo),top:jo}}function l(r,d){const o=t.getBoundingClientRect(),n=$n-d.width,g=o.width-$n,i=0,c=o.height-40;return{left:Math.max(n,Math.min(g,r.left)),top:Math.max(i,Math.min(c,r.top))}}function m(r,d,o={}){const n=o.persistKey??r,g=Xt(n),i=document.createElement("aside");i.className="extension-panel",i.dataset.panel=n;const c=document.createElement("div");c.className="extension-panel-header";const I=document.createElement("span");I.className="extension-panel-title",I.textContent=o.title??r,c.appendChild(I);const M=document.createElement("div");M.className="extension-panel-custom-btns",c.appendChild(M);function x(u){M.replaceChildren();for(const b of u){const S=document.createElement("button");S.className="extension-panel-btn",S.title=b.label,S.setAttribute("aria-label",b.label),S.textContent=b.iconText??b.label,b.disabled&&(S.disabled=!0),S.addEventListener("click",h=>{h.stopPropagation();try{b.onClick()}catch(T){console.error(`[backpack-viewer] panel header button "${b.label}" threw:`,T)}}),S.addEventListener("mousedown",h=>h.stopPropagation()),M.appendChild(S)}}x(o.headerButtons??[]);let F=!1,W=null,V=null;o.showFullscreenButton!==!1&&(W=document.createElement("button"),W.className="extension-panel-btn extension-panel-btn-fullscreen",W.title="Toggle fullscreen",W.setAttribute("aria-label","Toggle fullscreen"),V=Dn(),W.appendChild(V),W.addEventListener("click",u=>{u.stopPropagation(),p(!F)}),W.addEventListener("mousedown",u=>u.stopPropagation()),c.appendChild(W));let _=null;o.showCloseButton!==!1&&(_=document.createElement("button"),_.className="extension-panel-btn extension-panel-btn-close",_.title="Close panel",_.setAttribute("aria-label","Close panel"),_.textContent="×",_.addEventListener("click",u=>{var b;if(u.stopPropagation(),o.hideOnClose){be(!1);try{(b=o.onClose)==null||b.call(o)}catch(S){console.error("[backpack-viewer] panel onClose threw:",S)}}else ge()}),_.addEventListener("mousedown",u=>u.stopPropagation()),c.appendChild(_)),i.appendChild(c);const X=document.createElement("div");X.className="extension-panel-body",X.appendChild(d),i.appendChild(X),e.appendChild(i);const Y=g&&g.left!=null&&g.top!=null?{left:g.left,top:g.top}:o.defaultPosition??s(),q=l(Y,{width:Bn});i.style.left=q.left+"px",i.style.top=q.top+"px",dt(i);let me=0,U=0,pe=0,Ee=0,te=!1;function G(u){if(!te)return;const b=u.clientX-me,S=u.clientY-U,h=l({left:pe+b,top:Ee+S},i.getBoundingClientRect());i.style.left=h.left+"px",i.style.top=h.top+"px"}function ye(){if(!te)return;te=!1,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye);const u=i.getBoundingClientRect(),b=t.getBoundingClientRect();Fn(n,{...Xt(n),left:u.left-b.left,top:u.top-b.top})}c.addEventListener("mousedown",u=>{if(F)return;te=!0,me=u.clientX,U=u.clientY;const b=i.getBoundingClientRect(),S=t.getBoundingClientRect();pe=b.left-S.left,Ee=b.top-S.top,dt(i),document.addEventListener("mousemove",G),document.addEventListener("mouseup",ye),u.preventDefault()}),i.addEventListener("mousedown",()=>{F||dt(i)},{capture:!0});let Ce=!1,se=!0;function ge(){var u;if(!Ce){Ce=!0,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye),F&&(Ft(t,!1),F=!1),i.remove();try{(u=o.onClose)==null||u.call(o)}catch(b){console.error("[backpack-viewer] panel onClose threw:",b)}}}function be(u){u!==se&&(se=u,i.classList.toggle("is-hidden",!se),se?(dt(i),F&&Ft(t,!0)):F&&Ft(t,!1))}function p(u){var b;if(u!==F){F=u,i.classList.toggle("is-fullscreen",F),W&&V&&(V.remove(),V=F?Ho():Dn(),W.appendChild(V)),F?i.style.zIndex=String(Uo):dt(i),Ft(t,F),Fn(n,{...Xt(n),fullscreen:F});try{(b=o.onFullscreenChange)==null||b.call(o,F)}catch(S){console.error("[backpack-viewer] panel onFullscreenChange threw:",S)}}}g!=null&&g.fullscreen&&p(!0);function C(u){I.textContent=u}function E(u){x(u)}return{close:ge,setFullscreen:p,isFullscreen:()=>F,setTitle:C,setHeaderButtons:E,setVisible:be,isVisible:()=>se,bringToFront:()=>dt(i),element:d}}return{mount:m}}function Xn(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}function On(t,e){const s=e.toLowerCase();if(Xn(t).toLowerCase().includes(s)||t.type.toLowerCase().includes(s))return!0;for(const l of Object.values(t.properties))if(typeof l=="string"&&l.toLowerCase().includes(s))return!0;return!1}function qo(t,e){const s=(e==null?void 0:e.maxResults)??8,l=(e==null?void 0:e.debounceMs)??150;let m=null,r=null,d=null,o=null;const n=document.createElement("div");n.className="search-overlay hidden";const g=document.createElement("div");g.className="search-input-wrap";const i=document.createElement("input");i.className="search-input",i.type="text",i.placeholder="Search nodes...",i.setAttribute("autocomplete","off"),i.setAttribute("spellcheck","false");const c=document.createElement("kbd");c.className="search-kbd",c.textContent="/",g.appendChild(i),g.appendChild(c);const I=document.createElement("ul");I.className="search-results hidden",n.appendChild(g),n.appendChild(I),t.appendChild(n);function M(){if(!m)return null;const _=i.value.trim();if(_.length===0)return null;const X=new Set;for(const Y of m.nodes)On(Y,_)&&X.add(Y.id);return X}function x(){const _=M();r==null||r(_),F()}function F(){I.replaceChildren(),W=-1;const _=i.value.trim();if(!m||_.length===0){I.classList.add("hidden");return}const X=[];for(const Y of m.nodes)if(On(Y,_)&&(X.push(Y),X.length>=s))break;if(X.length===0){I.classList.add("hidden");return}for(const Y of X){const Z=document.createElement("li");Z.className="search-result-item";const q=document.createElement("span");q.className="search-result-dot",q.style.backgroundColor=Ae(Y.type);const me=document.createElement("span");me.className="search-result-label";const U=Xn(Y);me.textContent=U.length>36?U.slice(0,34)+"...":U;const pe=document.createElement("span");pe.className="search-result-type",pe.textContent=Y.type,Z.appendChild(q),Z.appendChild(me),Z.appendChild(pe),Z.addEventListener("click",()=>{d==null||d(Y.id),i.value="",I.classList.add("hidden"),x()}),I.appendChild(Z)}I.classList.remove("hidden")}i.addEventListener("input",()=>{o&&clearTimeout(o),o=setTimeout(x,l)});let W=-1;function V(){const _=I.querySelectorAll(".search-result-item");_.forEach((X,Y)=>{X.classList.toggle("search-result-active",Y===W)}),W>=0&&_[W]&&_[W].scrollIntoView({block:"nearest"})}return i.addEventListener("keydown",_=>{const X=I.querySelectorAll(".search-result-item");_.key==="ArrowDown"?(_.preventDefault(),X.length>0&&(W=Math.min(W+1,X.length-1),V())):_.key==="ArrowUp"?(_.preventDefault(),X.length>0&&(W=Math.max(W-1,0),V())):_.key==="Enter"?(_.preventDefault(),W>=0&&X[W]?X[W].click():X.length>0&&X[0].click(),i.blur()):_.key==="Escape"&&(i.value="",i.blur(),I.classList.add("hidden"),W=-1,x())}),document.addEventListener("click",_=>{n.contains(_.target)||I.classList.add("hidden")}),i.addEventListener("focus",()=>c.classList.add("hidden")),i.addEventListener("blur",()=>{i.value.length===0&&c.classList.remove("hidden")}),{setLearningGraphData(_){m=_,i.value="",I.classList.add("hidden"),m&&m.nodes.length>0?n.classList.remove("hidden"):n.classList.add("hidden")},onFilterChange(_){r=_},onNodeSelect(_){d=_},clear(){i.value="",I.classList.add("hidden"),r==null||r(null)},focus(){i.focus()}}}function Xo(t,e){let s=null,l=null,m=!0,r=null,d=!0,o=!0,n=!0,g="types",i="",c="",I=[],M=[];const x={types:new Set,nodeIds:new Set};function F(){if(!s)return[];const p=new Set;for(const C of s.nodes)x.types.has(C.type)&&p.add(C.id);for(const C of x.nodeIds)p.add(C);return[...p]}function W(p){if(x.nodeIds.has(p))return!0;const C=s==null?void 0:s.nodes.find(E=>E.id===p);return C?x.types.has(C.type):!1}function V(){return x.types.size===0&&x.nodeIds.size===0}function _(){const p=F();e.onFocusChange(p.length>0?p:null)}const X=document.createElement("button");X.className="tools-pane-toggle hidden",X.title="Graph Inspector",X.appendChild(at({size:16,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M4 7h16"}},{tag:"path",attrs:{d:"M4 12h16"}},{tag:"path",attrs:{d:"M4 17h10"}}]));const Y=document.createElement("div");Y.className="tools-pane-content hidden",t.appendChild(X),t.appendChild(Y),X.addEventListener("click",()=>{var p;m=!m,Y.classList.toggle("hidden",m),X.classList.toggle("active",!m),m||(p=e.onOpen)==null||p.call(e)});function Z(){if(Y.replaceChildren(),!l)return;const p=document.createElement("div");p.className="tools-pane-summary";const C=document.createElement("span");C.textContent=`${l.nodeCount} nodes`;const E=document.createElement("span");E.className="tools-pane-sep",E.textContent="·";const u=document.createElement("span");u.textContent=`${l.edgeCount} edges`;const b=document.createElement("span");b.className="tools-pane-sep",b.textContent="·";const S=document.createElement("span");if(S.textContent=`${l.types.length} types`,p.append(C,E,u,b,S),Y.appendChild(p),s&&l.nodeCount>0){const N=Math.ceil(JSON.stringify(s).length/4),L=Math.round(N/l.nodeCount),y=Math.max(10,Math.round(L*.3)*Math.min(5,l.nodeCount)),P=N>y?Math.round((1-y/N)*100):0,$=document.createElement("div");$.className="tools-pane-token-card";const K=Math.min(100,P),ae=document.createElement("div");ae.className="token-card-label",ae.textContent="Token Efficiency",$.appendChild(ae);const ce=document.createElement("div");ce.className="token-card-stat",ce.textContent=`~${N.toLocaleString()} tokens stored`,$.appendChild(ce);const ue=document.createElement("div");ue.className="token-card-bar";const ve=document.createElement("div");ve.className="token-card-bar-fill",ve.style.width=`${K}%`,ue.appendChild(ve),$.appendChild(ue);const $e=document.createElement("div");$e.className="token-card-stat",$e.textContent=`A search returns ~${y} tokens instead of ~${N.toLocaleString()} (${P}% reduction)`,$.appendChild($e),Y.appendChild($)}const h=document.createElement("div");h.className="tools-pane-tabs";const T=[{id:"types",label:"Types"},{id:"insights",label:"Insights"},{id:"controls",label:"Controls"}];for(const N of T){const L=document.createElement("button");L.className="tools-pane-tab",g===N.id&&L.classList.add("tools-pane-tab-active"),L.textContent=N.label,L.addEventListener("click",()=>{g=N.id,Z()}),h.appendChild(L)}Y.appendChild(h),V()||U(),M.length>0&&me(),g==="types"&&l.types.length>5?Y.appendChild(Ee("Filter types...",i,N=>{i=N,q()})):g==="insights"&&l.orphans.length+l.singletons.length+l.emptyNodes.length>5&&Y.appendChild(Ee("Filter issues...",c,L=>{c=L,q()}));const w=document.createElement("div");w.className="tools-pane-tab-content",Y.appendChild(w),q()}function q(){const p=Y.querySelector(".tools-pane-tab-content");p&&(p.replaceChildren(),g==="types"?te(p):g==="insights"?G(p):g==="controls"&&ye(p))}function me(){Y.appendChild(se(`Walk Trail (${M.length})`,p=>{for(let E=0;E<M.length;E++){const u=M[E],b=E===M.length-1;if(u.edgeType){const y=document.createElement("div");y.className="walk-trail-edge",y.textContent=`↓ ${u.edgeType}`,p.appendChild(y)}const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable",b&&(S.style.fontWeight="600");const h=document.createElement("span");h.className="tools-pane-count",h.style.minWidth="18px",h.textContent=`${E+1}`;const T=document.createElement("span");T.className="tools-pane-dot",T.style.backgroundColor=Ae(u.type);const w=document.createElement("span");w.className="tools-pane-name",w.textContent=u.label;const N=document.createElement("span");N.className="tools-pane-count",N.textContent=u.type;const L=document.createElement("button");L.className="tools-pane-edit",L.style.opacity="1",L.textContent="×",L.title="Remove from trail",L.addEventListener("click",y=>{var P;y.stopPropagation(),(P=e.onWalkTrailRemove)==null||P.call(e,u.id)}),S.appendChild(h),S.appendChild(T),S.appendChild(w),S.appendChild(N),S.appendChild(L),S.addEventListener("click",()=>{e.onNavigateToNode(u.id)}),p.appendChild(S)}const C=document.createElement("div");if(C.className="tools-pane-export-row",e.onWalkIsolate){const E=document.createElement("button");E.className="tools-pane-export-btn",E.textContent="Isolate (I)",E.addEventListener("click",()=>e.onWalkIsolate()),C.appendChild(E)}if(e.onWalkSaveSnippet&&M.length>=2){const E=document.createElement("button");E.className="tools-pane-export-btn",E.textContent="Save snippet",E.addEventListener("click",()=>{Dt("Save snippet","Name for this snippet").then(u=>{u&&e.onWalkSaveSnippet(u)})}),C.appendChild(E)}p.appendChild(C)}))}function U(){if(!l||!s)return;const p=F();Y.appendChild(se("Focused",C=>{for(const S of x.types){const h=l.types.find(P=>P.name===S);if(!h)continue;const T=document.createElement("div");T.className="tools-pane-row tools-pane-clickable";const w=document.createElement("span");w.className="tools-pane-dot",w.style.backgroundColor=Ae(h.name);const N=document.createElement("span");N.className="tools-pane-name",N.textContent=h.name;const L=document.createElement("span");L.className="tools-pane-count",L.textContent=`${h.count} nodes`;const y=document.createElement("button");y.className="tools-pane-edit tools-pane-focus-active",y.style.opacity="1",y.textContent="×",y.title=`Remove ${h.name} from focus`,T.appendChild(w),T.appendChild(N),T.appendChild(L),T.appendChild(y),y.addEventListener("click",P=>{P.stopPropagation(),x.types.delete(h.name),_(),Z()}),C.appendChild(T)}for(const S of x.nodeIds){const h=s.nodes.find($=>$.id===S);if(!h)continue;const T=Wn(h.properties)??h.id,w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("span");N.className="tools-pane-dot",N.style.backgroundColor=Ae(h.type);const L=document.createElement("span");L.className="tools-pane-name",L.textContent=T;const y=document.createElement("span");y.className="tools-pane-count",y.textContent=h.type;const P=document.createElement("button");P.className="tools-pane-edit tools-pane-focus-active",P.style.opacity="1",P.textContent="×",P.title=`Remove ${T} from focus`,w.appendChild(N),w.appendChild(L),w.appendChild(y),w.appendChild(P),w.addEventListener("click",$=>{$.target.closest(".tools-pane-edit")||e.onNavigateToNode(S)}),P.addEventListener("click",$=>{$.stopPropagation(),x.nodeIds.delete(S),_(),Z()}),C.appendChild(w)}const E=document.createElement("div");E.className="tools-pane-row tools-pane-clickable tools-pane-focus-clear";const u=document.createElement("span");u.className="tools-pane-name",u.style.color="var(--accent)",u.textContent=`${p.length} total`;const b=document.createElement("span");b.className="tools-pane-badge",b.textContent="clear all",E.appendChild(u),E.appendChild(b),E.addEventListener("click",()=>{x.types.clear(),x.nodeIds.clear(),_(),Z()}),C.appendChild(E)}))}function pe(p){const C=document.createElement("div");C.className="tools-pane-row tools-pane-clickable",r===p.name&&C.classList.add("active");const E=document.createElement("span");E.className="tools-pane-dot",E.style.backgroundColor=Ae(p.name);const u=document.createElement("span");u.className="tools-pane-name",u.textContent=p.name;const b=document.createElement("span");b.className="tools-pane-count",b.textContent=String(p.count);const S=document.createElement("button");S.className="tools-pane-edit tools-pane-focus-toggle",x.types.has(p.name)&&S.classList.add("tools-pane-focus-active"),S.textContent="◎",S.title=x.types.has(p.name)?`Remove ${p.name} from focus`:`Add ${p.name} to focus`;const h=document.createElement("button");return h.className="tools-pane-edit",h.textContent="✎",h.title=`Rename all ${p.name} nodes`,C.appendChild(E),C.appendChild(u),C.appendChild(b),C.appendChild(S),C.appendChild(h),C.addEventListener("click",T=>{T.target.closest(".tools-pane-edit")||(r===p.name?(r=null,e.onFilterByType(null)):(r=p.name,e.onFilterByType(p.name)),Z())}),S.addEventListener("click",T=>{T.stopPropagation(),x.types.has(p.name)?x.types.delete(p.name):x.types.add(p.name),_(),Z()}),h.addEventListener("click",T=>{T.stopPropagation(),ge(C,p.name,w=>{w&&w!==p.name&&e.onRenameNodeType(p.name,w)})}),C}function Ee(p,C,E){const u=document.createElement("input");return u.type="text",u.className="tools-pane-search",u.placeholder=p,u.value=C,u.addEventListener("input",()=>E(u.value)),u}function te(p){if(!l)return;const C=i.toLowerCase();if(l.types.length){const u=l.types.filter(b=>!x.types.has(b.name)).filter(b=>!C||b.name.toLowerCase().includes(C));u.length>0&&p.appendChild(se("Node Types",b=>{for(const S of u)b.appendChild(pe(S))}))}const E=l.edgeTypes.filter(u=>!C||u.name.toLowerCase().includes(C));E.length&&p.appendChild(se("Edge Types",u=>{for(const b of E){const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const h=document.createElement("span");h.className="tools-pane-name",h.textContent=b.name;const T=document.createElement("span");T.className="tools-pane-count",T.textContent=String(b.count);const w=document.createElement("button");w.className="tools-pane-edit",w.textContent="✎",w.title=`Rename all ${b.name} edges`,S.appendChild(h),S.appendChild(T),S.appendChild(w),w.addEventListener("click",N=>{N.stopPropagation(),ge(S,b.name,L=>{L&&L!==b.name&&e.onRenameEdgeType(b.name,L)})}),u.appendChild(S)}}))}function G(p){if(!l)return;const C=c.toLowerCase(),E=l.starred.filter(L=>!C||L.label.toLowerCase().includes(C)||L.type.toLowerCase().includes(C));E.length&&p.appendChild(se("★ Starred",L=>{for(const $ of E){const K=document.createElement("div");K.className="tools-pane-row tools-pane-clickable";const ae=document.createElement("span");ae.className="tools-pane-dot",ae.style.backgroundColor=Ae($.type);const ce=document.createElement("span");ce.className="tools-pane-name",ce.textContent=$.label;const ue=document.createElement("button");ue.className="tools-pane-edit tools-pane-focus-toggle",W($.id)&&ue.classList.add("tools-pane-focus-active"),ue.textContent="◎",ue.title=W($.id)?`Remove ${$.label} from focus`:`Add ${$.label} to focus`,K.appendChild(ae),K.appendChild(ce),K.appendChild(ue),K.addEventListener("click",ve=>{ve.target.closest(".tools-pane-edit")||e.onNavigateToNode($.id)}),ue.addEventListener("click",ve=>{ve.stopPropagation(),x.nodeIds.has($.id)?x.nodeIds.delete($.id):x.nodeIds.add($.id),_(),Z()}),L.appendChild(K)}const y=document.createElement("div");y.className="tools-pane-row tools-pane-actions";const P=document.createElement("button");if(P.className="tools-pane-action-btn",P.textContent="Focus all",P.title="Enter focus mode with all starred nodes",P.addEventListener("click",()=>{x.nodeIds.clear(),x.types.clear();for(const $ of l.starred)x.nodeIds.add($.id);_(),Z()}),y.appendChild(P),e.onStarredSaveSnippet){const $=document.createElement("button");$.className="tools-pane-action-btn",$.textContent="Save as snippet",$.title="Save starred nodes as a reusable snippet",$.addEventListener("click",async()=>{const K=await Dt("Snippet name","starred");K&&e.onStarredSaveSnippet(K,l.starred.map(ae=>ae.id))}),y.appendChild($)}L.appendChild(y)}));const u=l.mostConnected.filter(L=>!C||L.label.toLowerCase().includes(C)||L.type.toLowerCase().includes(C));u.length&&p.appendChild(se("Most Connected",L=>{for(const y of u){const P=document.createElement("div");P.className="tools-pane-row tools-pane-clickable";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(y.type);const K=document.createElement("span");K.className="tools-pane-name",K.textContent=y.label;const ae=document.createElement("span");ae.className="tools-pane-count",ae.textContent=`${y.connections}`;const ce=document.createElement("button");ce.className="tools-pane-edit tools-pane-focus-toggle",W(y.id)&&ce.classList.add("tools-pane-focus-active"),ce.textContent="◎",ce.title=W(y.id)?`Remove ${y.label} from focus`:`Add ${y.label} to focus`,P.appendChild($),P.appendChild(K),P.appendChild(ae),P.appendChild(ce),P.addEventListener("click",ue=>{ue.target.closest(".tools-pane-edit")||e.onNavigateToNode(y.id)}),ce.addEventListener("click",ue=>{ue.stopPropagation(),x.nodeIds.has(y.id)?x.nodeIds.delete(y.id):x.nodeIds.add(y.id),_(),Z()}),L.appendChild(P)}}));const b=l.orphans.filter(L=>!C||L.label.toLowerCase().includes(C)||L.type.toLowerCase().includes(C)),S=l.singletons.filter(L=>!C||L.name.toLowerCase().includes(C)),h=l.emptyNodes.filter(L=>!C||L.label.toLowerCase().includes(C)||L.type.toLowerCase().includes(C)),T=b.length>0,w=S.length>0,N=h.length>0;if(!T&&!w&&!N){const L=document.createElement("div");L.className="tools-pane-empty-msg",L.textContent="No issues found",p.appendChild(L);return}T&&p.appendChild(se("Orphans",L=>{for(const y of b.slice(0,5)){const P=document.createElement("div");P.className="tools-pane-row tools-pane-clickable tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(y.type);const K=document.createElement("span");K.className="tools-pane-name",K.textContent=y.label;const ae=document.createElement("span");ae.className="tools-pane-badge",ae.textContent="orphan";const ce=document.createElement("button");ce.className="tools-pane-edit tools-pane-focus-toggle",W(y.id)&&ce.classList.add("tools-pane-focus-active"),ce.textContent="◎",ce.title=W(y.id)?`Remove ${y.label} from focus`:`Add ${y.label} to focus`,P.appendChild($),P.appendChild(K),P.appendChild(ae),P.appendChild(ce),P.addEventListener("click",ue=>{ue.target.closest(".tools-pane-edit")||e.onNavigateToNode(y.id)}),ce.addEventListener("click",ue=>{ue.stopPropagation(),x.nodeIds.has(y.id)?x.nodeIds.delete(y.id):x.nodeIds.add(y.id),_(),Z()}),L.appendChild(P)}if(b.length>5){const y=document.createElement("div");y.className="tools-pane-more",y.textContent=`+ ${b.length-5} more orphans`,L.appendChild(y)}})),w&&p.appendChild(se("Singletons",L=>{for(const y of S.slice(0,5)){const P=document.createElement("div");P.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(y.name);const K=document.createElement("span");K.className="tools-pane-name",K.textContent=y.name;const ae=document.createElement("span");ae.className="tools-pane-badge",ae.textContent="1 node",P.appendChild($),P.appendChild(K),P.appendChild(ae),L.appendChild(P)}})),N&&p.appendChild(se("Empty Nodes",L=>{for(const y of h.slice(0,5)){const P=document.createElement("div");P.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(y.type);const K=document.createElement("span");K.className="tools-pane-name",K.textContent=y.label;const ae=document.createElement("span");ae.className="tools-pane-badge",ae.textContent="empty",P.appendChild($),P.appendChild(K),P.appendChild(ae),L.appendChild(P)}if(l.emptyNodes.length>5){const y=document.createElement("div");y.className="tools-pane-more",y.textContent=`+ ${l.emptyNodes.length-5} more empty nodes`,L.appendChild(y)}}))}function ye(p){p.appendChild(se("Display",C=>{const E=document.createElement("div");E.className="tools-pane-row tools-pane-clickable";const u=document.createElement("input");u.type="checkbox",u.checked=d,u.className="tools-pane-checkbox";const b=document.createElement("span");b.className="tools-pane-name",b.textContent="Edge labels",E.appendChild(u),E.appendChild(b),E.addEventListener("click",y=>{y.target!==u&&(u.checked=!u.checked),d=u.checked,e.onToggleEdgeLabels(d)}),C.appendChild(E);const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const h=document.createElement("input");h.type="checkbox",h.checked=o,h.className="tools-pane-checkbox";const T=document.createElement("span");T.className="tools-pane-name",T.textContent="Type regions",S.appendChild(h),S.appendChild(T),S.addEventListener("click",y=>{y.target!==h&&(h.checked=!h.checked),o=h.checked,e.onToggleTypeHulls(o)}),C.appendChild(S);const w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("input");N.type="checkbox",N.checked=n,N.className="tools-pane-checkbox";const L=document.createElement("span");L.className="tools-pane-name",L.textContent="Minimap",w.appendChild(N),w.appendChild(L),w.addEventListener("click",y=>{y.target!==N&&(N.checked=!N.checked),n=N.checked,e.onToggleMinimap(n)}),C.appendChild(w)})),p.appendChild(se("Layout",C=>{C.appendChild(Ce("Clustering",0,1,.02,.08,E=>{e.onLayoutChange("clusterStrength",E)})),C.appendChild(Ce("Spacing",.5,20,.5,1.5,E=>{e.onLayoutChange("spacing",E)})),C.appendChild(Ce("Pan speed",20,200,10,60,E=>{e.onPanSpeedChange(E)}))})),p.appendChild(se("Export",C=>{const E=document.createElement("div");E.className="tools-pane-export-row";const u=document.createElement("button");u.className="tools-pane-export-btn",u.textContent="Export PNG",u.addEventListener("click",()=>e.onExport("png"));const b=document.createElement("button");b.className="tools-pane-export-btn",b.textContent="Export SVG",b.addEventListener("click",()=>e.onExport("svg")),E.appendChild(u),E.appendChild(b),C.appendChild(E)})),(e.onSnapshot||e.onRollback)&&p.appendChild(se("Versions",C=>{const E=document.createElement("div");E.className="tools-pane-export-row";const u=document.createElement("button");if(u.className="tools-pane-export-btn",u.textContent="Save snapshot",u.addEventListener("click",()=>{Dt("Save snapshot","Label (optional)").then(b=>{var S;(S=e.onSnapshot)==null||S.call(e,b||void 0)})}),E.appendChild(u),C.appendChild(E),I.length>0)for(const b of I){const S=document.createElement("div");S.className="tools-pane-row";const h=document.createElement("span");h.className="tools-pane-name";const T=Go(b.timestamp);h.textContent=b.label?`#${b.version} ${b.label}`:`#${b.version}`,h.title=`${T} — ${b.nodeCount} nodes, ${b.edgeCount} edges`;const w=document.createElement("span");w.className="tools-pane-count",w.textContent=T;const N=document.createElement("button");N.className="tools-pane-edit",N.style.opacity="1",N.textContent="↩",N.title="Restore this snapshot",N.addEventListener("click",()=>{jn("Restore snapshot",`Restore snapshot #${b.version}? Current state will be lost unless you save a snapshot first.`).then(L=>{var y;L&&((y=e.onRollback)==null||y.call(e,b.version))})}),S.appendChild(h),S.appendChild(w),S.appendChild(N),C.appendChild(S)}else{const b=document.createElement("div");b.className="tools-pane-empty-msg",b.textContent="No snapshots yet",C.appendChild(b)}}))}function Ce(p,C,E,u,b,S){const h=document.createElement("div");h.className="tools-pane-slider-row";const T=document.createElement("span");T.className="tools-pane-slider-label",T.textContent=p;const w=document.createElement("input");w.type="range",w.className="tools-pane-slider",w.min=String(C),w.max=String(E),w.step=String(u),w.value=String(b);const N=document.createElement("span");return N.className="tools-pane-slider-value",N.textContent=String(b),w.addEventListener("input",()=>{const L=parseFloat(w.value);N.textContent=L%1===0?String(L):L.toFixed(2),S(L)}),h.appendChild(T),h.appendChild(w),h.appendChild(N),h}function se(p,C){const E=document.createElement("div");E.className="tools-pane-section";const u=document.createElement("div");return u.className="tools-pane-heading",u.textContent=p,E.appendChild(u),C(E),E}function ge(p,C,E){const u=document.createElement("input");u.className="tools-pane-inline-input",u.value=C,u.type="text";const b=ho(p);p.replaceChildren(u),p.classList.add("tools-pane-editing"),u.focus(),u.select();function S(){fo(p,b)}function h(){const T=u.value.trim();p.classList.remove("tools-pane-editing"),T&&T!==C?E(T):S()}u.addEventListener("keydown",T=>{T.key==="Enter"&&(T.preventDefault(),h()),T.key==="Escape"&&(S(),p.classList.remove("tools-pane-editing"))}),u.addEventListener("blur",h)}function be(p){const C=new Map,E=new Map,u=new Map,b=new Set;for(const y of p.nodes)C.set(y.type,(C.get(y.type)??0)+1);for(const y of p.edges)E.set(y.type,(E.get(y.type)??0)+1),u.set(y.sourceId,(u.get(y.sourceId)??0)+1),u.set(y.targetId,(u.get(y.targetId)??0)+1),b.add(y.sourceId),b.add(y.targetId);const S=y=>Wn(y.properties)??y.id,h=p.nodes.filter(y=>y.properties._starred===!0).map(y=>({id:y.id,label:S(y),type:y.type})),T=p.nodes.filter(y=>!b.has(y.id)).map(y=>({id:y.id,label:S(y),type:y.type})),w=[...C.entries()].filter(([,y])=>y===1).map(([y])=>({name:y})),N=p.nodes.filter(y=>Object.keys(y.properties).length===0).map(y=>({id:y.id,label:y.id,type:y.type})),L=p.nodes.map(y=>({id:y.id,label:S(y),type:y.type,connections:u.get(y.id)??0})).filter(y=>y.connections>0).sort((y,P)=>P.connections-y.connections).slice(0,5);return{nodeCount:p.nodes.length,edgeCount:p.edges.length,types:[...C.entries()].sort((y,P)=>P[1]-y[1]).map(([y,P])=>({name:y,count:P})),edgeTypes:[...E.entries()].sort((y,P)=>P[1]-y[1]).map(([y,P])=>({name:y,count:P})),starred:h,orphans:T,singletons:w,emptyNodes:N,mostConnected:L}}return{collapse(){m=!0,Y.classList.add("hidden"),X.classList.remove("active")},addToFocusSet(p){for(const C of p)x.nodeIds.add(C);_(),Z()},clearFocusSet(){x.types.clear(),x.nodeIds.clear(),_(),Z()},setData(p){s=p,r=null,x.types.clear(),x.nodeIds.clear(),s&&s.nodes.length>0?(l=be(s),X.classList.remove("hidden"),Z()):(l=null,X.classList.add("hidden"),Y.classList.add("hidden"))},setSnapshots(p){I=p,g==="controls"&&q()},setWalkTrail(p){M=p,Z()}}}function Go(t){const e=Date.now()-new Date(t).getTime(),s=Math.floor(e/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;const l=Math.floor(s/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function Wn(t){for(const e of Object.values(t))if(typeof e=="string")return e;return null}function Vo(t,e){const s=e.split("+"),l=s.pop(),m=s.map(n=>n.toLowerCase()),r=m.includes("ctrl")||m.includes("cmd")||m.includes("meta"),d=m.includes("shift"),o=m.includes("alt");return r!==(t.ctrlKey||t.metaKey)||!r&&(t.ctrlKey||t.metaKey)||d&&!t.shiftKey||o!==t.altKey?!1:l.toLowerCase()==="escape"?t.key==="Escape":l.toLowerCase()==="tab"?t.key==="Tab":m.length>0?t.key.toLowerCase()===l.toLowerCase():t.key===l}function Jo(){return{search:"Focus search",searchAlt:"Focus search (alt)",undo:"Undo",redo:"Redo",help:"Toggle help",escape:"Exit focus / close panel",focus:"Focus on selected / exit focus",toggleEdges:"Toggle edges on/off",center:"Center view on graph",nextNode:"Next node in view",prevNode:"Previous node in view",nextConnection:"Next connection",prevConnection:"Previous connection",historyBack:"Node history back",historyForward:"Node history forward",hopsIncrease:"Increase hops",hopsDecrease:"Decrease hops",panLeft:"Pan left",panDown:"Pan down",panUp:"Pan up",panRight:"Pan right",panFastLeft:"Pan fast left",zoomOut:"Zoom out",zoomIn:"Zoom in",panFastRight:"Pan fast right",spacingDecrease:"Decrease spacing",spacingIncrease:"Increase spacing",clusteringDecrease:"Decrease clustering",clusteringIncrease:"Increase clustering",toggleSidebar:"Toggle sidebar",walkMode:"Toggle walk mode (in focus)",walkIsolate:"Isolate walk trail nodes",resetPins:"Release all pinned nodes (reset manual layout)"}}const Ko=[{key:"Click",description:"Select node"},{key:"Shift+Click",description:"Multi-select nodes"},{key:"Drag node",description:"Move & pin node (temporary)"},{key:"Drag selection",description:"Move selected group (temporary)"},{key:"Shift+drag empty",description:"Rubber-band select"},{key:"Drag empty",description:"Pan canvas"},{key:"Scroll",description:"Zoom in/out"}],Zo=["search","searchAlt","undo","redo","help","focus","toggleEdges","center","nextNode","prevNode","nextConnection","prevConnection","historyBack","historyForward","hopsIncrease","hopsDecrease","panLeft","panDown","panUp","panRight","panFastLeft","panFastRight","zoomIn","zoomOut","spacingDecrease","spacingIncrease","clusteringDecrease","clusteringIncrease","toggleSidebar","walkMode","walkIsolate","resetPins","escape"];function Qo(t){return t.split("+").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("+")}function es(t,e){const s=Jo(),l=document.createElement("div");l.className="shortcuts-overlay hidden";const m=document.createElement("div");m.className="shortcuts-modal";const r=document.createElement("h3");r.className="shortcuts-title",r.textContent="Keyboard Shortcuts";const d=document.createElement("div");d.className="shortcuts-list";for(const c of Zo){const I=e[c];if(!I)continue;const M=document.createElement("div");M.className="shortcuts-row";const x=document.createElement("div");x.className="shortcuts-keys";const F=document.createElement("kbd");F.textContent=Qo(I),x.appendChild(F);const W=document.createElement("span");W.className="shortcuts-desc",W.textContent=s[c],M.appendChild(x),M.appendChild(W),d.appendChild(M)}for(const c of Ko){const I=document.createElement("div");I.className="shortcuts-row";const M=document.createElement("div");M.className="shortcuts-keys";const x=document.createElement("kbd");x.textContent=c.key,M.appendChild(x);const F=document.createElement("span");F.className="shortcuts-desc",F.textContent=c.description,I.appendChild(M),I.appendChild(F),d.appendChild(I)}const o=document.createElement("button");o.className="shortcuts-close",o.textContent="×",m.appendChild(o),m.appendChild(r),m.appendChild(d),l.appendChild(m),t.appendChild(l);function n(){l.classList.remove("hidden")}function g(){l.classList.add("hidden")}function i(){l.classList.toggle("hidden")}return o.addEventListener("click",g),l.addEventListener("click",c=>{c.target===l&&g()}),{show:n,hide:g,toggle:i}}function ts(t){const e=document.createElement("div");e.className="empty-state";const s=document.createElement("div");s.className="empty-state-bg";for(const M of["c1","c2","c3","c4","c5"]){const x=document.createElement("div");x.className=`empty-state-circle ${M}`,s.appendChild(x)}s.appendChild(at({size:0,viewBox:"0 0 400 300",className:"empty-state-lines"},[{tag:"line",attrs:{x1:80,y1:60,x2:220,y2:140,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:320,y2:80,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:160,y2:240,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:160,y1:240,x2:300,y2:220,"stroke-width":"0.5",opacity:"0.15"}}]));const l=s.querySelector(".empty-state-lines");l&&(l.removeAttribute("width"),l.removeAttribute("height"),l.setAttribute("preserveAspectRatio","xMidYMid slice")),e.appendChild(s);const m=document.createElement("div");m.className="empty-state-content";const r=document.createElement("div");r.className="empty-state-icon",r.appendChild(at({size:48,strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0022 16z"}},{tag:"polyline",attrs:{points:"3.27 6.96 12 12.01 20.73 6.96"}},{tag:"line",attrs:{x1:12,y1:22.08,x2:12,y2:12}}])),m.appendChild(r);const d=document.createElement("h2");d.className="empty-state-title",d.textContent="No learning graphs yet",m.appendChild(d);const o=document.createElement("p");o.className="empty-state-desc",o.textContent="Connect Backpack to Claude, then start a conversation. Claude will build your first learning graph automatically.",m.appendChild(o);const n=document.createElement("div");n.className="empty-state-setup";const g=document.createElement("div");g.className="empty-state-label",g.textContent="Add Backpack to Claude Code:";const i=document.createElement("code");i.className="empty-state-code",i.textContent="claude mcp add backpack-local -s user -- npx backpack-ontology@latest",n.append(g,i),m.appendChild(n);const c=document.createElement("p");c.className="empty-state-hint",c.append("Press ");const I=document.createElement("kbd");return I.textContent="?",c.appendChild(I),c.append(" for keyboard shortcuts"),m.appendChild(c),e.appendChild(m),t.appendChild(e),{show(){e.classList.remove("hidden")},hide(){e.classList.add("hidden")}}}const ns=30;function os(){let t=[],e=[];return{push(s){t.push(JSON.stringify(s)),t.length>ns&&t.shift(),e=[]},undo(s){return t.length===0?null:(e.push(JSON.stringify(s)),JSON.parse(t.pop()))},redo(s){return e.length===0?null:(t.push(JSON.stringify(s)),JSON.parse(e.pop()))},canUndo(){return t.length>0},canRedo(){return e.length>0},clear(){t=[],e=[]}}}function ss(t,e){let s=null;function l(d,o,n,g,i){m(),s=document.createElement("div"),s.className="context-menu",s.style.left=`${g}px`,s.style.top=`${i}px`;const c=[{label:n?"★ Unstar":"☆ Star",action:()=>e.onStar(d),premium:!1},{label:"◎ Focus on node",action:()=>e.onFocusNode(d),premium:!1},{label:"⑂ Explore in branch",action:()=>e.onExploreInBranch(d),premium:!1},{label:"⎘ Copy ID",action:()=>e.onCopyId(d),premium:!1}];e.onExpand&&c.push({label:"⊕ Expand node",action:()=>e.onExpand(d),premium:!0}),e.onExplainPath&&c.push({label:"↔ Explain path to…",action:()=>e.onExplainPath(d),premium:!0}),e.onEnrich&&c.push({label:"≡ Enrich from web",action:()=>e.onEnrich(d),premium:!0});let I=!1;for(const x of c){if(!I&&x.premium){const W=document.createElement("div");W.className="context-menu-separator",s.appendChild(W),I=!0}const F=document.createElement("div");F.className="context-menu-item",F.textContent=x.label,F.addEventListener("click",()=>{x.action(),m()}),s.appendChild(F)}t.appendChild(s);const M=s.getBoundingClientRect();M.right>window.innerWidth&&(s.style.left=`${g-M.width}px`),M.bottom>window.innerHeight&&(s.style.top=`${i-M.height}px`),setTimeout(()=>document.addEventListener("click",m),0),document.addEventListener("keydown",r)}function m(){s&&(s.remove(),s=null),document.removeEventListener("click",m),document.removeEventListener("keydown",r)}function r(d){d.key==="Escape"&&m()}return{show:l,hide:m}}function as(t){const e=document.createElement("button");return e.className="copy-prompt-btn",e.title="Copy a prompt about the current view to clipboard",e.textContent="Copy Prompt",e.addEventListener("click",async()=>{const s=t();if(!s.graphName||!s.data){kt("No graph loaded");return}const l=cs(s);try{await navigator.clipboard.writeText(l),kt("Prompt copied — paste into Claude")}catch{kt("Failed to copy to clipboard")}}),e}function Un(t){return Object.values(t.properties).find(s=>typeof s=="string")??t.id}function cs(t){const{graphName:e,data:s,selection:l,focus:m}=t,r=[];r.push(`I'm looking at the Backpack learning graph "${e}" in the viewer.`),r.push(`It has ${s.nodes.length} nodes and ${s.edges.length} edges.`);const d=new Map;for(const o of s.nodes)d.set(o.type,(d.get(o.type)??0)+1);if(d.size>0){const o=Array.from(d.entries()).sort((n,g)=>g[1]-n[1]).slice(0,8).map(([n,g])=>`${n} (${g})`).join(", ");r.push(`Node types: ${o}`)}if(m&&m.seedNodeIds.length>0){r.push(""),r.push(`I'm focused on ${m.seedNodeIds.length} seed node(s) at ${m.hops} hop(s):`);for(const o of m.seedNodeIds.slice(0,10)){const n=s.nodes.find(g=>g.id===o);n&&r.push(`- ${Un(n)} (type: ${n.type})`)}}if(l.length>0){r.push(""),r.push(`I have ${l.length} node(s) selected:`);for(const o of l.slice(0,20)){const n=s.nodes.find(i=>i.id===o);if(!n)continue;const g=Object.entries(n.properties).filter(([i])=>!i.startsWith("_")).slice(0,5).map(([i,c])=>`${i}=${JSON.stringify(c)}`).join(", ");r.push(`- ${Un(n)} (type: ${n.type}, id: ${o}${g?`, ${g}`:""})`)}}return r.push(""),r.push("If you have access to the Backpack MCP tools, please use them to answer questions about this graph (backpack_get_node, backpack_get_neighbors, backpack_search, etc)."),r.push(""),r.push("My question: "),r.join(`
|
|
6
|
+
`)}const is=200;let Gt=null,Vt=null;function ls(t){Gt=t,Vt===null&&(Vt=window.setTimeout(async()=>{const e=Gt;if(Gt=null,Vt=null,!!e)try{await fetch("/api/viewer-state",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({...e,updatedAt:new Date().toISOString()})})}catch{}},is))}function rs(){const t=new Map;return{emit(e){const s=t.get(e);if(s)for(const l of s)try{l()}catch(m){console.error(`[backpack-viewer] event handler for ${e} threw:`,m)}},subscribe(e,s){let l=t.get(e);return l||(l=new Set,t.set(e,l)),l.add(s),()=>{const m=t.get(e);m==null||m.delete(s)}}}}const tn="1";function ds(t,e,s,l){function m(){return Date.now().toString(36)+Math.random().toString(36).slice(2,10)}function r(){const d=e.getGraph();if(!d)throw new Error("no graph loaded in viewer");return d}return{name:t,viewerApiVersion:tn,getGraph:()=>e.getGraph(),getGraphName:()=>e.getGraphName(),getSelection:()=>e.getSelection(),getFocus:()=>e.getFocus(),on(d,o){return e.subscribe(d,o)},async addNode(d,o){if(!d)throw new Error("addNode: type is required");const n=r();e.snapshotForUndo();const g=m(),i=new Date().toISOString();return n.nodes.push({id:g,type:d,properties:o,createdAt:i,updatedAt:i}),await e.saveCurrentGraph(),g},async updateNode(d,o){const g=r().nodes.find(i=>i.id===d);if(!g)throw new Error(`updateNode: node not found: ${d}`);e.snapshotForUndo(),g.properties={...g.properties,...o},g.updatedAt=new Date().toISOString(),await e.saveCurrentGraph()},async removeNode(d){const o=r();if(!o.nodes.find(g=>g.id===d))throw new Error(`removeNode: node not found: ${d}`);e.snapshotForUndo(),o.nodes=o.nodes.filter(g=>g.id!==d),o.edges=o.edges.filter(g=>g.sourceId!==d&&g.targetId!==d),await e.saveCurrentGraph()},async addEdge(d,o,n){if(!d||!o||!n)throw new Error("addEdge: sourceId, targetId, and type are required");const g=r();if(!g.nodes.find(c=>c.id===d))throw new Error(`addEdge: source not found: ${d}`);if(!g.nodes.find(c=>c.id===o))throw new Error(`addEdge: target not found: ${o}`);e.snapshotForUndo();const i=m();return g.edges.push({id:i,sourceId:d,targetId:o,type:n}),await e.saveCurrentGraph(),i},async removeEdge(d){const o=r();if(!o.edges.find(g=>g.id===d))throw new Error(`removeEdge: edge not found: ${d}`);e.snapshotForUndo(),o.edges=o.edges.filter(g=>g.id!==d),await e.saveCurrentGraph()},panToNode:d=>e.panToNode(d),focusNodes:(d,o)=>e.focusNodes(d,o),exitFocus:()=>e.exitFocus(),registerTaskbarIcon(d){return s.register(d)},mountPanel(d,o){return l.mount(t,d,o)},settings:{async get(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings`,n=await fetch(o);if(!n.ok)return null;const g=await n.json();return d in g?g[d]:null},async set(d,o){const n=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,g=await fetch(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({value:o})});if(!g.ok){const i=await g.text().catch(()=>"");throw new Error(`settings.set failed: ${i||g.status}`)}},async remove(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,n=await fetch(o,{method:"DELETE"});if(!n.ok){const g=await n.text().catch(()=>"");throw new Error(`settings.remove failed: ${g||n.status}`)}}},async fetch(d,o={}){const n=`/api/extensions/${encodeURIComponent(t)}/fetch`,g={};if(o.headers)if(o.headers instanceof Headers)o.headers.forEach((c,I)=>{g[I]=c});else if(Array.isArray(o.headers))for(const[c,I]of o.headers)g[c]=I;else Object.assign(g,o.headers);const i=typeof o.body=="string"||o.body==null?o.body:(()=>{throw new Error("viewer.fetch only supports string bodies in v1")})();return fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:d,method:o.method??"POST",headers:g,body:i})})}}}const ps="bottom-right";function us(t){const e={"top-left":t.topLeft,"top-right":t.topRight,"bottom-left":t.bottomLeft,"bottom-center":t.bottomCenter,"bottom-right":t.bottomRight},s={"top-left":0,"top-right":0,"bottom-left":0,"bottom-center":0,"bottom-right":0};function l(r){e[r].classList.toggle("has-icons",s[r]>0)}l("top-left"),l("top-right"),l("bottom-left"),l("bottom-center"),l("bottom-right");function m(r){const d=r.position??ps,o=e[d];if(!o)throw new Error(`unknown taskbar position: ${d}`);const n=document.createElement("button");if(n.className="extension-taskbar-icon",n.title=r.label,n.setAttribute("aria-label",r.label),r.iconText){const i=document.createElement("span");i.className="extension-taskbar-icon-symbol",i.textContent=r.iconText,n.appendChild(i)}const g=document.createElement("span");return g.className="extension-taskbar-icon-label",g.textContent=r.label,n.appendChild(g),n.addEventListener("click",()=>{try{r.onClick()}catch(i){console.error(`[backpack-viewer] taskbar icon "${r.label}" onClick threw:`,i)}}),o.appendChild(n),s[d]++,l(d),()=>{n.remove(),s[d]=Math.max(0,s[d]-1),l(d)}}return{register:m}}async function ms(t,e){const s=us(t.taskbarSlots);let l=[];try{const r=await fetch("/api/extensions");if(!r.ok)return console.warn(`[backpack-viewer] /api/extensions returned ${r.status}; no extensions will be loaded`),[];l=await r.json()}catch(r){return console.error(`[backpack-viewer] failed to fetch extensions list: ${r.message}`),[]}const m=[];for(const r of l){if(r.viewerApi!==tn){console.warn(`[backpack-viewer] extension "${r.name}" targets viewerApi "${r.viewerApi}" but this viewer supports "${tn}"; skipping`);continue}if(r.stylesheet)try{hs(r.name,r.stylesheet)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" stylesheet load failed:`,o)}const d=ds(r.name,t,s,e);try{const g=(await import(`/extensions/${encodeURIComponent(r.name)}/${r.entry}`)).activate;if(typeof g!="function"){console.error(`[backpack-viewer] extension "${r.name}" has no exported activate(api) function; skipping`);continue}await g(d),m.push({info:r,api:d}),console.log(`[backpack-viewer] loaded extension "${r.name}" v${r.version}`)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" failed to activate:`,o)}}return m}function hs(t,e){if(e.includes(".."))throw new Error(`stylesheet path "${e}" is invalid`);const s=document.createElement("link");s.rel="stylesheet",s.href=`/extensions/${encodeURIComponent(t)}/${e}`,s.dataset.extension=t,document.head.appendChild(s)}const fs={search:"/",searchAlt:"ctrl+k",undo:"ctrl+z",redo:"ctrl+shift+z",help:"?",escape:"Escape",focus:"f",toggleEdges:"e",center:"c",nextNode:".",prevNode:",",nextConnection:">",prevConnection:"<",historyBack:"(",historyForward:")",hopsIncrease:"=",hopsDecrease:"-",panLeft:"h",panDown:"j",panUp:"k",panRight:"l",panFastLeft:"H",zoomOut:"J",zoomIn:"K",panFastRight:"L",spacingDecrease:"[",spacingIncrease:"]",clusteringDecrease:"{",clusteringIncrease:"}",toggleSidebar:"Tab",walkMode:"w",walkIsolate:"i",resetPins:"r"},gs={host:"127.0.0.1",port:5173},ys={edges:!0,edgeLabels:!0,typeHulls:!0,minimap:!0,theme:"system"},Cs={spacing:1.5,clustering:.08},bs={panSpeed:60,panFastMultiplier:3,zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300},vs={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15},xs={pulseSpeed:.02},Es={maxSearchResults:8,maxQualityItems:5,maxMostConnected:5,searchDebounceMs:150},ws={disabled:[],external:[]},ks={keybindings:fs,server:gs,display:ys,layout:Cs,navigation:bs,lod:vs,walk:xs,limits:Es,extensions:ws};let ie="",A=null,Jt=new Set,Kt=!1;async function Ss(){var St,mt;const t=document.getElementById("canvas-container"),e={...ks};try{const a=await fetch("/api/config");if(a.ok){const v=await a.json();Object.assign(e.keybindings,v.keybindings??{}),Object.assign(e.display,v.display??{}),Object.assign(e.layout,v.layout??{}),Object.assign(e.navigation,v.navigation??{}),Object.assign(e.lod,v.lod??{}),Object.assign(e.limits,v.limits??{})}}catch{}const s=e.keybindings,l=window.matchMedia("(prefers-color-scheme: dark)"),m=e.display.theme==="system"?l.matches?"dark":"light":e.display.theme,d=localStorage.getItem("backpack-theme")??m;document.documentElement.setAttribute("data-theme",d);const o=document.createElement("button");o.className="theme-toggle",o.textContent=d==="light"?"☾":"☼",o.title="Toggle light/dark mode",o.addEventListener("click",()=>{const v=document.documentElement.getAttribute("data-theme")==="light"?"dark":"light";document.documentElement.setAttribute("data-theme",v),localStorage.setItem("backpack-theme",v),o.textContent=v==="light"?"☾":"☼"}),t.appendChild(o);const n=os();async function g(){if(!ie||!A)return;A.metadata.updatedAt=new Date().toISOString(),await zt(ie,A),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A);const a=await vt();P.setSummaries(a),pe.emit("graph-changed")}async function i(a){A=a,await zt(ie,A),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A);const v=await vt();P.setSummaries(v)}let c;const I=Yo(t),M=Fo(t,I,{onUpdateNode(a,v){if(!A)return;n.push(A);const R=A.nodes.find(j=>j.id===a);R&&(R.properties={...R.properties,...v},R.updatedAt=new Date().toISOString(),g().then(()=>M.show([a],A)))},onChangeNodeType(a,v){if(!A)return;n.push(A);const R=A.nodes.find(j=>j.id===a);R&&(R.type=v,R.updatedAt=new Date().toISOString(),g().then(()=>M.show([a],A)))},onDeleteNode(a){A&&(n.push(A),A.nodes=A.nodes.filter(v=>v.id!==a),A.edges=A.edges.filter(v=>v.sourceId!==a&&v.targetId!==a),g())},onDeleteEdge(a){var R;if(!A)return;n.push(A);const v=(R=A.edges.find(j=>j.id===a))==null?void 0:R.sourceId;A.edges=A.edges.filter(j=>j.id!==a),g().then(()=>{v&&A&&M.show([v],A)})},onAddProperty(a,v,R){if(!A)return;n.push(A);const j=A.nodes.find(ne=>ne.id===a);j&&(j.properties[v]=R,j.updatedAt=new Date().toISOString(),g().then(()=>M.show([a],A)))}},a=>{c.panToNode(a)},a=>{G.addToFocusSet(a)}),x=window.matchMedia("(max-width: 768px)");let F=[],W=e.display.edges,V=e.navigation.panSpeed,_=-1,X=null;function Y(a){X&&X.remove(),X=document.createElement("div"),X.className="focus-indicator";const v=document.createElement("span");v.className="focus-indicator-label",v.textContent=`Focused: ${a.totalNodes} nodes`;const R=document.createElement("span");R.className="focus-indicator-hops",R.textContent=`${a.hops}`;const j=document.createElement("button");j.className="focus-indicator-btn",j.textContent="−",j.title="Fewer hops",j.disabled=a.hops===0,j.addEventListener("click",()=>{c.enterFocus(a.seedNodeIds,Math.max(0,a.hops-1))});const ne=document.createElement("button");ne.className="focus-indicator-btn",ne.textContent="+",ne.title="More hops",ne.disabled=!1,ne.addEventListener("click",()=>{c.enterFocus(a.seedNodeIds,a.hops+1)});const de=document.createElement("button");de.className="focus-indicator-btn focus-indicator-exit",de.textContent="×",de.title="Exit focus (Esc)",de.addEventListener("click",()=>G.clearFocusSet());const le=document.createElement("button");le.className="walk-indicator",c.getWalkMode()&&le.classList.add("active"),le.textContent="Walk",le.title="Toggle walk mode (W) — click nodes to traverse",le.addEventListener("click",()=>{c.setWalkMode(!c.getWalkMode()),le.classList.toggle("active",c.getWalkMode())}),X.appendChild(v),X.appendChild(j),X.appendChild(R),X.appendChild(ne),X.appendChild(le),X.appendChild(de)}function Z(){X&&(X.remove(),X=null)}const q=document.createElement("div");q.className="path-bar hidden";function me(a){if(q.replaceChildren(),!A)return;for(let R=0;R<a.nodeIds.length;R++){const j=a.nodeIds[R],ne=A.nodes.find(he=>he.id===j);if(!ne)continue;const de=Object.values(ne.properties).find(he=>typeof he=="string")??ne.id;if(R>0){const he=a.edgeIds[R-1],Me=A.edges.find(Ge=>Ge.id===he),xe=document.createElement("span");xe.className="path-bar-edge",xe.textContent=Me?`→ ${Me.type} →`:"→",q.appendChild(xe)}const le=document.createElement("span");le.className="path-bar-node",le.textContent=de,le.addEventListener("click",()=>c.panToNode(j)),q.appendChild(le)}const v=document.createElement("button");v.className="path-bar-close",v.textContent="×",v.addEventListener("click",U),q.appendChild(v),q.classList.remove("hidden")}function U(){q.classList.add("hidden"),q.replaceChildren(),c.clearHighlightedPath()}const pe=rs();function Ee(){ie&&ls({graph:ie,selection:F,focus:(c==null?void 0:c.getFocusInfo())??null})}c=Bo(t,a=>{if(F=a??[],Ee(),pe.emit("selection-changed"),!c.getWalkMode())if(a&&a.length===2){const v=c.findPath(a[0],a[1]);v&&v.nodeIds.length>0?(c.setHighlightedPath(v.nodeIds,v.edgeIds),me(v)):U()}else U();a&&a.length>0&&A?(M.show(a,A),x.matches&&G.collapse(),Re(ie,a)):(M.hide(),ie&&Re(ie))},a=>{if(a){Y(a);const v=t.querySelector(".canvas-top-left");v&&X&&v.appendChild(X),Re(ie,a.seedNodeIds),M.setFocusDisabled(a.hops===0),K()}else Z(),M.setFocusDisabled(!1),ie&&Re(ie),K();Ee(),pe.emit("focus-changed")},{lod:e.lod,navigation:e.navigation,walk:e.walk});const te=qo(t,{maxResults:e.limits.maxSearchResults,debounceMs:e.limits.searchDebounceMs}),G=Xo(t,{onFilterByType(a){if(A)if(a===null)c.setFilteredNodeIds(null);else{const v=new Set(((A==null?void 0:A.nodes)??[]).filter(R=>R.type===a).map(R=>R.id));c.setFilteredNodeIds(v)}},onNavigateToNode(a){c.panToNode(a),A&&M.show([a],A)},onWalkTrailRemove(a){c.removeFromWalkTrail(a),K()},onWalkIsolate(){if(!A)return;const a=c.getWalkTrail();a.length!==0&&c.enterFocus(a,0)},async onWalkSaveSnippet(a){if(!ie||!A)return;const v=c.getWalkTrail();if(v.length<2)return;const R=new Set(v),j=A.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ie,a,v,j),await ue(ie)},async onStarredSaveSnippet(a,v){if(!ie||!A)return;const R=new Set(v),j=A.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ie,a,v,j),await ue(ie)},onFocusChange(a){a&&a.length>0?c.enterFocus(a,0):c.isFocused()&&c.exitFocus()},onRenameNodeType(a,v){if(A){n.push(A);for(const R of A.nodes)R.type===a&&(R.type=v,R.updatedAt=new Date().toISOString());g()}},onRenameEdgeType(a,v){if(A){n.push(A);for(const R of A.edges)R.type===a&&(R.type=v);g()}},onToggleEdgeLabels(a){c.setEdgeLabels(a)},onToggleTypeHulls(a){c.setTypeHulls(a)},onToggleMinimap(a){c.setMinimap(a)},onLayoutChange(a,v){lt({[a]:v}),c.reheat()},onPanSpeedChange(a){V=a},onExport(a){const v=c.exportImage(a);if(!v)return;const R=document.createElement("a");R.download=`${ie||"graph"}.${a}`,R.href=v,R.click()},onSnapshot:async a=>{ie&&(await io(ie,a),await ce(ie))},onRollback:async a=>{ie&&(await lo(ie,a),A=await Pt(ie),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A),await ce(ie))},onOpen(){x.matches&&M.hide()}}),ye=document.createElement("div");ye.className="canvas-top-bar";const Ce=document.createElement("div");Ce.className="canvas-top-left";const se=document.createElement("div");se.className="canvas-top-center";const ge=document.createElement("div");ge.className="canvas-top-right";const be=t.querySelector(".tools-pane-toggle");be&&Ce.appendChild(be);const p=t.querySelector(".zoom-controls");p&&ge.appendChild(p),ge.appendChild(o);const C=document.createElement("div");C.className="ext-slot ext-slot-top-left",se.appendChild(C);const E=t.querySelector(".search-overlay");E&&se.appendChild(E);const u=document.createElement("div");u.className="ext-slot ext-slot-top-right",se.appendChild(u);const b=as(()=>({graphName:ie,data:A,selection:F,focus:c.getFocusInfo()}));se.appendChild(b),ye.appendChild(Ce),ye.appendChild(se),ye.appendChild(ge),t.appendChild(ye);const S=document.createElement("div");S.className="canvas-bottom-bar";const h=document.createElement("div");h.className="canvas-bottom-left";const T=document.createElement("div");T.className="canvas-bottom-center";const w=document.createElement("div");w.className="canvas-bottom-right";const N=document.createElement("div");N.className="ext-slot ext-slot-bottom-left",h.appendChild(N);const L=document.createElement("div");L.className="ext-slot ext-slot-bottom-center",T.appendChild(L),T.appendChild(q);const y=document.createElement("div");y.className="ext-slot ext-slot-bottom-right",w.appendChild(y),S.appendChild(h),S.appendChild(T),S.appendChild(w),t.appendChild(S),te.onFilterChange(a=>{c.setFilteredNodeIds(a)}),te.onNodeSelect(a=>{c.isFocused()&&G.clearFocusSet(),c.panToNode(a),A&&M.show([a],A)});const P=go(document.getElementById("sidebar"),{onSelect:a=>ct(a),onRename:async(a,v)=>{await oo(a,v),ie===a&&(ie=v);const R=await vt();P.setSummaries(R),P.setActive(ie),ie===v&&(A=await Pt(v),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A))},onBranchSwitch:async(a,v)=>{await gn(a,v),await ae(a),A=await Pt(a),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A),await ce(a)},onBranchCreate:async(a,v)=>{await fn(a,v),await ae(a)},onBranchDelete:async(a,v)=>{await ao(a,v),await ae(a)},onSnippetLoad:async(a,v)=>{var j;const R=await po(a,v);((j=R==null?void 0:R.nodeIds)==null?void 0:j.length)>0&&c.enterFocus(R.nodeIds,0)},onSnippetDelete:async(a,v)=>{await uo(a,v),await ue(a)},onBackpackSwitch:async a=>{await fetch("/api/backpacks/switch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:a})}),await $()},onBackpackRegister:async(a,v)=>{await fetch("/api/backpacks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:a,activate:v})}),await $()}});async function $(){try{const v=await(await fetch("/api/backpacks")).json();P.setBackpacks(v)}catch{}try{const a=await vt();P.setSummaries(a),ie&&!a.some(v=>v.name===ie)&&(ie="",A=null,c.loadGraph({metadata:{name:"",description:"",createdAt:"",updatedAt:""},nodes:[],edges:[]}))}catch{}}function K(){const a=c.getWalkTrail();if(!A||a.length===0){G.setWalkTrail([]),U();return}const v=[],R=a.map((j,ne)=>{const de=A.nodes.find(he=>he.id===j);let le;if(ne>0){const he=a[ne-1],Me=A.edges.find(xe=>xe.sourceId===he&&xe.targetId===j||xe.targetId===he&&xe.sourceId===j);le=Me==null?void 0:Me.type,Me&&v.push(Me.id)}return{id:j,label:de?Object.values(de.properties).find(he=>typeof he=="string")??de.id:j,type:(de==null?void 0:de.type)??"?",edgeType:le}});G.setWalkTrail(R),a.length>=2?(c.setHighlightedPath(a,v),me({nodeIds:a,edgeIds:v})):U()}async function ae(a){const v=await so(a),R=v.find(j=>j.active);R&&P.setActiveBranch(a,R.name,v)}async function ce(a){const v=await co(a);G.setSnapshots(v)}async function ue(a){const v=await ro(a);P.setSnippets(a,v)}Ce.insertBefore(P.expandBtn,Ce.firstChild);const ve=es(t,s),$e=ts(t),Qe=ss(t,{onStar(a){if(!A)return;const v=A.nodes.find(j=>j.id===a);if(!v)return;const R=v.properties._starred===!0;v.properties._starred=!R,zt(ie,A),c.loadGraph(A)},onFocusNode(a){G.addToFocusSet([a])},onExploreInBranch(a){if(ie){const v=`explore-${a.slice(0,8)}`;fn(ie,v).then(()=>{gn(ie,v).then(()=>{c.enterFocus([a],1)})})}},onCopyId(a){navigator.clipboard.writeText(a)}});t.addEventListener("contextmenu",a=>{a.preventDefault();const v=t.querySelector("canvas");if(!v||!A)return;const R=v.getBoundingClientRect(),j=a.clientX-R.left,ne=a.clientY-R.top,de=c.nodeAtScreen(j,ne);if(!de)return;const le=A.nodes.find(xe=>xe.id===de.id);if(!le)return;const he=Object.values(le.properties).find(xe=>typeof xe=="string")??le.id,Me=le.properties._starred===!0;Qe.show(le.id,he,Me,a.clientX-R.left,a.clientY-R.top)}),e.display.edges||c.setEdges(!1),e.display.edgeLabels||c.setEdgeLabels(!1),e.display.typeHulls||c.setTypeHulls(!1),e.display.minimap||c.setMinimap(!1);function Re(a,v){const R=[];v!=null&&v.length&&R.push("node="+v.map(encodeURIComponent).join(","));const j=c.getFocusInfo();j&&(R.push("focus="+j.seedNodeIds.map(encodeURIComponent).join(",")),R.push("hops="+j.hops));const ne="#"+encodeURIComponent(a)+(R.length?"?"+R.join("&"):"");history.replaceState(null,"",ne)}function et(){const a=window.location.hash.slice(1);if(!a)return{graph:null,nodes:[],focus:[],hops:1};const[v,R]=a.split("?"),j=v?decodeURIComponent(v):null;let ne=[],de=[],le=1;if(R){const he=new URLSearchParams(R),Me=he.get("node");Me&&(ne=Me.split(",").map(decodeURIComponent));const xe=he.get("focus");xe&&(de=xe.split(",").map(decodeURIComponent));const Ge=he.get("hops");Ge&&(le=Math.max(0,parseInt(Ge,10)||1))}return{graph:j,nodes:ne,focus:de,hops:le}}async function ct(a,v,R,j){ie=a,Kt=Jt.has(a),P.setActive(a),M.hide(),Z(),te.clear(),n.clear(),A=Kt?await no(a):await Pt(a);const ne=xo(A.nodes.length);if(lt({spacing:Math.max(e.layout.spacing,ne.spacing),clusterStrength:Math.max(e.layout.clustering,ne.clusterStrength)}),c.loadGraph(A),te.setLearningGraphData(A),G.setData(A),$e.hide(),Re(a),Ee(),pe.emit("graph-switched"),pe.emit("graph-changed"),Kt||(await ae(a),await ce(a),await ue(a)),R!=null&&R.length&&A){const de=R.filter(le=>A.nodes.some(he=>he.id===le));if(de.length){setTimeout(()=>{c.enterFocus(de,j??1)},500);return}}if(v!=null&&v.length&&A){const de=v.filter(le=>A.nodes.some(he=>he.id===le));de.length&&setTimeout(()=>{c.panToNodes(de),A&&M.show(de,A),Re(a,de)},500)}}try{const v=await(await fetch("/api/backpacks")).json();P.setBackpacks(v)}catch{}fetch("/api/version-check").then(a=>a.json()).then(a=>{a.stale&&a.latest&&P.setStaleVersionBanner(a.current,a.latest)}).catch(()=>{});const Xe=new URLSearchParams(window.location.search).get("share");if(Xe)try{const a=await fetch(`/v1/share/${Xe}/meta`);if(!a.ok)throw new Error("Share link not found or expired");const v=await a.json(),R=await fetch(`/v1/share/${Xe}`);if(!R.ok)throw new Error("Failed to download shared backpack");const j=new Uint8Array(await R.arrayBuffer());if(j.length<9||j[0]!==66||j[1]!==80||j[2]!==65||j[3]!==75)throw new Error("Invalid share data: not a BPAK envelope");const ne=new DataView(j.buffer,j.byteOffset,j.byteLength).getUint32(5,!1);if(9+ne>j.length)throw new Error("Invalid envelope: header length exceeds data");const de=JSON.parse(new TextDecoder().decode(j.slice(9,9+ne))),le=j.slice(9+ne);let he;if(de.format!=="plaintext"){const Me=window.location.hash.slice(1),xe=new URLSearchParams(Me).get("k")??Me.split("k=")[1];if(!xe)throw new Error("Missing decryption key in URL fragment");const{Decrypter:Ge}=await eo(async()=>{const{Decrypter:ft}=await import("./index-Dz__sU13.js");return{Decrypter:ft}},[]),Nt=atob(xe.replace(/-/g,"+").replace(/_/g,"/")),ht=new Ge;ht.addIdentity(Nt);const Lt=await ht.decrypt(le);he=JSON.parse(new TextDecoder().decode(Lt))}else he=JSON.parse(new TextDecoder().decode(le));ie=v.backpack_name||"Shared Backpack",A=he,c.loadGraph(he),te.setLearningGraphData(he),P.setSummaries([{name:ie,description:"",nodeCount:((St=he.nodes)==null?void 0:St.length)??0,edgeCount:((mt=he.edges)==null?void 0:mt.length)??0,nodeTypes:[]}]),P.setActive(ie),document.title=`${ie} — Backpack`}catch(a){const v=a instanceof Error?a.message:"Failed to load shared backpack";kt(v,5e3),$e.show()}else{const[a,v]=await Promise.all([vt(),to().catch(()=>[])]);P.setSummaries(a),P.setRemotes(v),Jt=new Set(v.map(ne=>ne.name));const R=et(),j=R.graph&&a.some(ne=>ne.name===R.graph)||R.graph&&Jt.has(R.graph)?R.graph:a.length>0?a[0].name:v.length>0?v[0].name:null;j?await ct(j,R.nodes.length?R.nodes:void 0,R.focus.length?R.focus:void 0,R.hops):$e.show()}ms({getGraph:()=>A,getGraphName:()=>ie,getSelection:()=>[...F],getFocus:()=>c.getFocusInfo(),saveCurrentGraph:async()=>{await g()},snapshotForUndo:()=>{A&&n.push(A)},panToNode:a=>c.panToNode(a),focusNodes:(a,v)=>c.enterFocus(a,v),exitFocus:()=>{c.isFocused()&&c.exitFocus()},taskbarSlots:{topLeft:C,topRight:u,bottomLeft:N,bottomCenter:L,bottomRight:y},subscribe:(a,v)=>pe.subscribe(a,v)},I).catch(a=>{console.error("[backpack-viewer] extension loader failed:",a)});const ut={search(){te.focus()},searchAlt(){te.focus()},undo(){if(A){const a=n.undo(A);a&&i(a)}},redo(){if(A){const a=n.redo(A);a&&i(a)}},focus(){c.isFocused()?G.clearFocusSet():F.length>0&&G.addToFocusSet(F)},hopsDecrease(){const a=c.getFocusInfo();a&&a.hops>0&&c.enterFocus(a.seedNodeIds,a.hops-1)},hopsIncrease(){const a=c.getFocusInfo();a&&c.enterFocus(a.seedNodeIds,a.hops+1)},nextNode(){const a=c.getNodeIds();a.length>0&&(_=(_+1)%a.length,c.panToNode(a[_]),A&&M.show([a[_]],A))},prevNode(){const a=c.getNodeIds();a.length>0&&(_=_<=0?a.length-1:_-1,c.panToNode(a[_]),A&&M.show([a[_]],A))},nextConnection(){const a=M.cycleConnection(1);a&&c.panToNode(a)},prevConnection(){const a=M.cycleConnection(-1);a&&c.panToNode(a)},historyBack(){M.goBack()},historyForward(){M.goForward()},center(){c.centerView()},toggleEdges(){W=!W,c.setEdges(W)},panLeft(){c.panBy(-V,0)},panDown(){c.panBy(0,V)},panUp(){c.panBy(0,-V)},panRight(){c.panBy(V,0)},panFastLeft(){c.panBy(-V*e.navigation.panFastMultiplier,0)},zoomOut(){c.zoomBy(1/e.navigation.zoomFactor)},zoomIn(){c.zoomBy(e.navigation.zoomFactor)},panFastRight(){c.panBy(V*e.navigation.panFastMultiplier,0)},spacingDecrease(){const a=wt();lt({spacing:Math.max(.5,a.spacing-.5)}),c.reheat()},spacingIncrease(){const a=wt();lt({spacing:Math.min(20,a.spacing+.5)}),c.reheat()},clusteringDecrease(){const a=wt();lt({clusterStrength:Math.max(0,a.clusterStrength-.03)}),c.reheat()},clusteringIncrease(){const a=wt();lt({clusterStrength:Math.min(1,a.clusterStrength+.03)}),c.reheat()},help(){ve.toggle()},toggleSidebar(){P.toggle()},resetPins(){c.releaseAllPins()&&kt("Manual layout reset — pins released")},walkIsolate(){if(!A)return;const a=c.getWalkTrail();a.length!==0&&c.enterFocus(a,0)},walkMode(){!c.isFocused()&&F.length>0&&G.addToFocusSet(F),c.setWalkMode(!c.getWalkMode());const a=t.querySelector(".walk-indicator");a&&a.classList.toggle("active",c.getWalkMode()),K()},escape(){c.getSelectedNodeIds().length>0?c.clearSelection():c.isFocused()?G.clearFocusSet():ve.hide()}};document.addEventListener("keydown",a=>{var v;if(!(a.target instanceof HTMLInputElement||a.target instanceof HTMLTextAreaElement)){for(const[R,j]of Object.entries(s))if(Vo(a,j)){(R==="search"||R==="searchAlt"||R==="undo"||R==="redo"||R==="toggleSidebar")&&a.preventDefault(),(v=ut[R])==null||v.call(ut);return}}}),window.addEventListener("hashchange",()=>{const a=et();if(a.graph&&a.graph!==ie)ct(a.graph,a.nodes.length?a.nodes:void 0,a.focus.length?a.focus:void 0,a.hops);else if(a.graph&&a.focus.length&&A)c.enterFocus(a.focus,a.hops);else if(a.graph&&a.nodes.length&&A){c.isFocused()&&c.exitFocus();const v=a.nodes.filter(R=>A.nodes.some(j=>j.id===R));v.length&&(c.panToNodes(v),M.show(v,A))}})}Ss();
|
package/dist/app/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>Backpack Viewer</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-DpElI3pz.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Cab62Pxr.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="app">
|