@skill-map/cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/tutorial/sm-tutorial.md +8 -0
- package/dist/cli.js +8246 -5744
- package/dist/cli.js.map +1 -1
- package/dist/conformance/index.js +36 -14
- package/dist/conformance/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +529 -61
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +418 -85
- package/dist/kernel/index.js +529 -61
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/002_sidecar_columns.sql +53 -0
- package/dist/migrations/003_drop_node_author.sql +20 -0
- package/dist/migrations/004_sidecar_root_json.sql +23 -0
- package/dist/migrations/005_node_favorites.sql +20 -0
- package/dist/ui/chunk-3R7E3HPC.js +7 -0
- package/dist/ui/chunk-JKJGGXCS.js +1025 -0
- package/dist/ui/chunk-SX2A3WBX.js +247 -0
- package/dist/ui/{chunk-WMWULWZX.js → chunk-TWZHUCAT.js} +1 -1
- package/dist/ui/chunk-UJOZYR5I.js +1 -0
- package/dist/ui/chunk-WTAL2RK4.js +1 -0
- package/dist/ui/{chunk-LUDNWV6G.js → chunk-Z3UJHHTC.js} +38 -38
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-AAYGMON4.js +1 -0
- package/migrations/002_sidecar_columns.sql +53 -0
- package/migrations/003_drop_node_author.sql +20 -0
- package/migrations/004_sidecar_root_json.sql +23 -0
- package/migrations/005_node_favorites.sql +20 -0
- package/package.json +6 -6
- package/dist/ui/chunk-5ZGVBIPP.js +0 -1031
- package/dist/ui/chunk-BWUDZKB6.js +0 -247
- package/dist/ui/main-7LR4JN4M.js +0 -1
package/dist/ui/index.html
CHANGED
|
@@ -23,5 +23,5 @@
|
|
|
23
23
|
<style>:root{--ff-white:#ffffff;--ff-black:#000000;--ff-gray-0:#ffffff;--ff-gray-25:#fcfcfc;--ff-gray-50:#f8f8f7;--ff-gray-75:#f2f2f0;--ff-gray-100:#e9e9e6;--ff-gray-150:#dcdcd7;--ff-gray-200:#c9c9c1;--ff-gray-300:#afafa5;--ff-gray-400:#8d8d81;--ff-gray-500:#69695f;--ff-gray-600:#505048;--ff-gray-700:#3c3c36;--ff-gray-800:#272722;--ff-gray-900:#1b1b18;--ff-gray-950:#141412;--ff-gray-1000:#0f0f0d;--ff-alpha-black-04:rgba(15, 15, 13, .04);--ff-alpha-black-06:rgba(15, 15, 13, .06);--ff-alpha-black-08:rgba(15, 15, 13, .08);--ff-alpha-black-10:rgba(15, 15, 13, .1);--ff-alpha-black-12:rgba(15, 15, 13, .12);--ff-alpha-black-15:rgba(15, 15, 13, .15);--ff-alpha-black-20:rgba(15, 15, 13, .2);--ff-alpha-black-30:rgba(15, 15, 13, .3);--ff-alpha-black-40:rgba(15, 15, 13, .4);--ff-alpha-black-60:rgba(15, 15, 13, .6);--ff-alpha-white-04:rgba(255, 255, 255, .04);--ff-alpha-white-06:rgba(255, 255, 255, .06);--ff-alpha-white-08:rgba(255, 255, 255, .08);--ff-alpha-white-10:rgba(255, 255, 255, .1);--ff-alpha-white-12:rgba(255, 255, 255, .12);--ff-alpha-white-15:rgba(255, 255, 255, .15);--ff-alpha-white-20:rgba(255, 255, 255, .2);--ff-alpha-white-30:rgba(255, 255, 255, .3);--ff-alpha-white-40:rgba(255, 255, 255, .4);--ff-alpha-white-60:rgba(255, 255, 255, .6);--ff-blue-100:#e8f2ff;--ff-blue-200:#bad8ff;--ff-blue-300:#7db7ff;--ff-blue-400:#4176ff;--ff-blue-500:#2759db;--ff-blue-600:#1b3f9e;--ff-green-100:#e7f7ef;--ff-green-300:#71c795;--ff-green-400:#2b9b5f;--ff-green-500:#1e7748;--ff-yellow-100:#fff5de;--ff-yellow-300:#e1b354;--ff-yellow-400:#bb8121;--ff-yellow-500:#916112;--ff-red-100:#feeceb;--ff-red-300:#e48d85;--ff-red-400:#c55245;--ff-red-500:#9e3a2f;--ff-radius-4:4px;--ff-radius-6:6px;--ff-radius-pill:999px;--ff-font-family-sans:"Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--ff-font-family-mono:ui-monospace, "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;--ff-font-size-xs:12px;--ff-font-size-sm:14px;--ff-font-size-md:16px;--ff-font-size-lg:18px;--ff-shadow-1:0 1px 2px rgba(15, 15, 13, .05), 0 8px 20px rgba(15, 15, 13, .04);--ff-shadow-2:0 10px 28px rgba(15, 15, 13, .08), 0 3px 10px rgba(15, 15, 13, .05);--ff-shadow-3:0 18px 48px rgba(15, 15, 13, .12), 0 6px 16px rgba(15, 15, 13, .08)}:root{--ff-color-surface-page:var(--ff-gray-25);--ff-color-surface-canvas:var(--ff-gray-25);--ff-color-surface-card:var(--ff-white);--ff-color-surface-group:rgba(65, 118, 255, .14);--ff-color-surface-group-active:rgba(65, 118, 255, .2);--ff-color-surface-muted:var(--ff-gray-50);--ff-color-surface-soft:var(--ff-gray-75);--ff-color-surface-accent-soft:rgba(65, 118, 255, .1);--ff-color-border-default:var(--ff-alpha-black-12);--ff-color-border-subtle:var(--ff-alpha-black-08);--ff-color-border-strong:var(--ff-alpha-black-20);--ff-color-border-accent:var(--ff-blue-500);--ff-color-text-primary:var(--ff-gray-800);--ff-color-text-secondary:var(--ff-gray-500);--ff-color-text-tertiary:var(--ff-gray-400);--ff-color-text-inverse:var(--ff-white);--ff-color-accent:var(--ff-blue-500);--ff-color-accent-strong:var(--ff-blue-600);--ff-color-success:var(--ff-green-400);--ff-color-warning:var(--ff-yellow-400);--ff-color-danger:var(--ff-red-400);--ff-color-disabled-surface:var(--ff-gray-100);--ff-color-disabled-border:var(--ff-alpha-black-10);--ff-color-disabled-text:var(--ff-gray-300);--ff-color-selection-fill:rgba(65, 118, 255, .12);--ff-color-selection-stroke:rgba(65, 118, 255, .28);--ff-color-grid:var(--ff-alpha-black-08);--ff-color-grid-strong:var(--ff-alpha-black-15);--ff-color-connector-connected:var(--ff-blue-500);--ff-color-connection:var(--ff-gray-600);--ff-color-connection-muted:var(--ff-gray-300);--ff-color-connection-hover:var(--ff-alpha-black-12);--ff-color-grouping-drop-target-border:var(--ff-gray-800);--ff-color-grouping-drop-target-border-active:var(--ff-gray-800);--ff-color-waypoint-fill:var(--ff-white);--ff-color-waypoint-stroke:var(--ff-blue-500);--ff-color-waypoint-candidate-fill:var(--ff-white);--ff-color-waypoint-candidate-stroke:var(--ff-green-400);--ff-color-minimap-surface:var(--ff-white);--ff-color-minimap-node:var(--ff-gray-700);--ff-color-minimap-view:rgba(65, 118, 255, .14);--ff-color-magnetic-line:var(--ff-blue-500);--ff-color-magnetic-rect-fill:rgba(65, 118, 255, .08);--ff-color-magnetic-rect-border:rgba(65, 118, 255, .24);--ff-radius-node:var(--ff-radius-4);--ff-radius-group:var(--ff-radius-4);--ff-radius-control:var(--ff-radius-4);--ff-radius-socket-square:var(--ff-radius-6);--ff-radius-pill:var(--ff-radius-pill);--ff-font-sans:var(--ff-font-family-sans);--ff-font-mono:var(--ff-font-family-mono);--ff-font-size-body:var(--ff-font-size-sm);--ff-font-size-label:var(--ff-font-size-xs);--ff-shadow-surface:var(--ff-shadow-1);--ff-shadow-floating:var(--ff-shadow-2)}:root{--ff-flow-background-color:var(--ff-color-surface-page);--ff-flow-text-color:var(--ff-color-text-primary);--ff-flow-font-family:var(--ff-font-sans);--ff-flow-font-size:var(--ff-font-size-body);--ff-canvas-background-color:var(--ff-color-surface-canvas);--ff-node-background-color:var(--ff-color-surface-card);--ff-node-background-color-inverse:var(--ff-color-text-primary);--ff-node-border-color:var(--ff-color-border-default);--ff-node-border-color-selected:var(--ff-color-border-accent);--ff-node-color:var(--ff-color-text-primary);--ff-node-border-radius:var(--ff-radius-node);--ff-node-shadow:var(--ff-shadow-surface);--ff-node-shadow-selected:var(--ff-shadow-floating);--ff-node-width:120px;--ff-node-min-height:56px;--ff-node-padding:24px;--ff-group-background-color:var(--ff-color-surface-group);--ff-group-background-color-active:var(--ff-color-surface-group-active);--ff-group-border-color:var(--ff-color-border-subtle);--ff-group-border-color-selected:var(--ff-color-border-accent);--ff-group-border-color-active:var(--ff-color-border-accent);--ff-group-color:var(--ff-color-text-secondary);--ff-group-border-radius:var(--ff-radius-group);--ff-group-min-width:180px;--ff-group-min-height:120px;--ff-group-padding:24px;--ff-grouping-drop-target-border-color:var(--ff-color-grouping-drop-target-border);--ff-grouping-drop-target-border-style:dashed;--ff-grouping-drop-target-border-width:1px;--ff-grouping-drop-target-border-color-active:var(--ff-color-grouping-drop-target-border-active);--ff-grouping-drop-target-border-style-active:dashed;--ff-grouping-drop-target-border-width-active:2px;--ff-handle-background-color:var(--ff-color-surface-card);--ff-handle-border-color:var(--ff-color-border-strong);--ff-handle-color:var(--ff-color-text-secondary);--ff-handle-size:12px;--ff-handle-radius:var(--ff-radius-control);--ff-rotate-handle-size:16px;--ff-connector-background-color:var(--ff-color-surface-card);--ff-connector-border-color:var(--ff-color-border-default);--ff-connector-connected-color:var(--ff-color-connector-connected);--ff-connector-accent-color:var(--ff-color-accent);--ff-connector-disabled-color:var(--ff-color-disabled-surface);--ff-connector-disabled-border-color:var(--ff-color-disabled-border);--ff-connector-size:16px;--ff-connector-node-ring-color:var(--ff-canvas-background-color);--ff-outlet-background-color:var(--ff-color-surface-muted);--ff-outlet-border-color:var(--ff-color-border-default);--ff-outlet-color:var(--ff-color-accent);--ff-outlet-disabled-background-color:var(--ff-color-disabled-surface);--ff-outlet-disabled-border-color:var(--ff-color-disabled-border);--ff-outlet-disabled-color:var(--ff-color-disabled-text);--ff-outlet-border-radius:var(--ff-radius-pill);--ff-outlet-padding-y:6px;--ff-outlet-padding-x:12px;--ff-connection-color:var(--ff-color-connection);--ff-snap-connection-color:var(--ff-color-connection-muted);--ff-connection-hover-color:var(--ff-color-connection-hover);--ff-connection-selected-color:var(--ff-color-accent);--ff-connection-label-color:var(--ff-color-text-secondary);--ff-connection-content-color:var(--ff-node-color);--ff-connection-content-background-color:var(--ff-node-background-color);--ff-connection-content-border-color:var(--ff-node-border-color);--ff-connection-content-border-color-selected:var(--ff-connection-selected-color);--ff-connection-content-border-radius:var(--ff-node-border-radius);--ff-connection-content-font-size:13px;--ff-connection-content-padding-y:2px;--ff-connection-content-padding-x:8px;--ff-connection-width:2px;--ff-connection-hit-width:14px;--ff-connection-drag-handle-fill:var(--ff-color-surface-card);--ff-connection-drag-handle-stroke:var(--ff-color-accent);--ff-marker-color:var(--ff-connection-color);--ff-waypoint-fill:var(--ff-color-waypoint-fill);--ff-waypoint-stroke:var(--ff-color-waypoint-stroke);--ff-waypoint-candidate-fill:var(--ff-color-waypoint-candidate-fill);--ff-waypoint-candidate-stroke:var(--ff-color-waypoint-candidate-stroke);--ff-background-line-color:var(--ff-color-grid);--ff-background-dot-color:var(--ff-color-grid-strong);--ff-selection-area-color:var(--ff-color-selection-fill);--ff-selection-area-border-color:var(--ff-color-selection-stroke);--ff-minimap-background-color:var(--ff-color-minimap-surface);--ff-minimap-border-color:var(--ff-color-border-default);--ff-minimap-node-color:var(--ff-color-minimap-node);--ff-minimap-node-selected-color:var(--ff-color-accent);--ff-minimap-view-color:var(--ff-color-minimap-view);--ff-minimap-view-border-color:var(--ff-color-selection-stroke);--ff-minimap-border-radius:var(--ff-radius-node);--ff-minimap-shadow:var(--ff-shadow-floating);--ff-magnetic-line-color:var(--ff-color-magnetic-line);--ff-magnetic-rect-fill:var(--ff-color-magnetic-rect-fill);--ff-magnetic-rect-border-color:var(--ff-color-magnetic-rect-border);--ff-external-item-background-color:var(--ff-color-surface-card);--ff-external-item-border-color:var(--ff-color-border-default);--ff-external-item-color:var(--ff-color-text-primary);--ff-external-item-disabled-color:var(--ff-color-disabled-text);--ff-external-item-disabled-background-color:var(--ff-color-disabled-surface);--ff-external-item-border-radius:var(--ff-radius-node);--ff-external-item-shadow:var(--ff-shadow-surface);--ff-external-item-preview-shadow:var(--ff-shadow-floating);--ff-external-item-placeholder-background-color:var(--ff-color-surface-soft);--ff-external-item-placeholder-border-color:var(--ff-color-border-subtle)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}:root{--sm-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;--sm-bg-page:#f8fafc;--sm-bg-content:#ffffff;--sm-bg-hover:#f1f5f9;--sm-border:#e2e8f0;--sm-nav-active-bg:#eff6ff;--sm-violet-50:#F5F3FF;--sm-violet-100:#EDE9FE;--sm-violet-200:#DDD6FE;--sm-violet-300:#C4B5FD;--sm-violet-400:#A78BFA;--sm-violet-500:#8B5CF6;--sm-violet-600:#7C3AED;--sm-violet-700:#6D28D9;--sm-violet-800:#4C1D95;--sm-violet-900:#2E1065;--sm-edge-invokes:#f59e0b;--sm-edge-references:#3b82f6;--sm-edge-mentions:#9ca3af;--sm-edge-supersedes:#8b5cf6;--sm-link-in-bg:#e0e7ff;--sm-link-in-fg:#3730a3;--sm-link-out-bg:#fef3c7;--sm-link-out-fg:#92400e;--sm-severity-info:#1e3a8a;--sm-severity-success:#065f46;--sm-severity-warn:#92400e;--sm-severity-error:#991b1b;--sm-severity-warn-bg:rgba(254, 243, 199, .35);--sm-severity-error-bg:rgba(254, 226, 226, .35);--sm-shadow-topbar:0 1px 2px rgba(0, 0, 0, .03);--sm-shadow-eventlog:0 -4px 16px rgba(0, 0, 0, .08);--sm-shadow-floating:0 4px 14px rgba(0, 0, 0, .08);--sm-shadow-card:0 1px 2px rgba(0, 0, 0, .05);--sm-shadow-card-hover:0 3px 12px rgba(0, 0, 0, .12)}html,body{margin:0;padding:0;height:100dvh;overflow:hidden;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:var(--sm-bg-page);color:var(--p-text-color)}*,*:before,*:after{box-sizing:border-box}</style><link rel="stylesheet" href="styles-CBPFNGXA.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-CBPFNGXA.css"></noscript></head>
|
|
24
24
|
<body>
|
|
25
25
|
<app-root></app-root>
|
|
26
|
-
<link rel="modulepreload" href="chunk-
|
|
26
|
+
<link rel="modulepreload" href="chunk-WTAL2RK4.js"><link rel="modulepreload" href="chunk-JKJGGXCS.js"><link rel="modulepreload" href="chunk-3R7E3HPC.js"><link rel="modulepreload" href="chunk-Q7L6LLAK.js"><script src="main-AAYGMON4.js" type="module"></script></body>
|
|
27
27
|
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as De}from"./chunk-WTAL2RK4.js";import{$ as B,A as C,B as $,Bb as fe,Cb as ve,Db as ye,Eb as be,Fb as ke,Gb as Ie,H as j,Hb as _e,Ia as d,Ib as we,Ja as p,K as a,Ka as Q,Q as U,Ub as Se,Vb as Pe,Wb as Ae,X as ce,Y as de,a as te,aa as W,b as re,c as O,cb as v,ea as T,f as x,fa as l,ga as c,ha as A,j as ne,l as k,lc as H,mc as z,n as ie,o as F,p as s,qa as me,qc as Ee,r as oe,rc as Te,s as se,sa as K,sc as Re,ta as D,tc as m,uc as Me,v as ae,vb as pe,w as N,wb as ue,xb as R,xc as I,yb as he,yc as xe,z as le,zb as ge,zc as Ce}from"./chunk-JKJGGXCS.js";import"./chunk-3R7E3HPC.js";import"./chunk-Q7L6LLAK.js";var Le=[{path:"",pathMatch:"full",redirectTo:"graph"},{path:"graph",loadComponent:()=>import("./chunk-SX2A3WBX.js").then(r=>r.GraphView),data:{title:"Graph"}},{path:"list",loadComponent:()=>import("./chunk-Z3UJHHTC.js").then(r=>r.ListView),data:{title:"List"}},{path:"**",redirectTo:"graph"}];var y={errors:{unknownMode:r=>`SKILL_MAP_MODE: unknown value "${r}"`,restPrefix:r=>`BFF error [${r}]: `,malformedResponse:"BFF returned a malformed response",demoFetchFailed:(r,e)=>`Demo bundle fetch failed for "${r}": ${e}`,demoParseFailed:(r,e)=>`Demo bundle parse failed for "${r}": ${e}`,graphFormatNotInDemo:r=>`Graph format "${r}" is not bundled in demo mode (only "ascii").`}};var _=new ie("SKILL_MAP_MODE");function Oe(){return typeof document>"u"?"live":document.querySelector('meta[name="skill-map-mode"]')?.content==="demo"?"demo":"live"}var u={connected:r=>`[ws] connected to ${r}`,closed:(r,e)=>`[ws] closed (code=${r}, reason="${e}")`,malformedFrame:r=>`[ws] malformed frame dropped: ${r}`,socketError:r=>`[ws] socket error: ${r}`,reconnectScheduled:(r,e)=>`[ws] reconnect attempt ${e} scheduled in ${r}ms`,reconnectGiveUp:r=>`[ws] giving up after ${r} failed reconnect attempts`};var Fe=[1e3,2e3,4e3,8e3,16e3,3e4],ee=10,Ye=new Set([1e3,1001]);function Ze(){return typeof window>"u"||!window.location?"ws://127.0.0.1:4242/ws":`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/ws`}var w=class r{mode=s(_);destroyRef=s(N);subject=new re;socket=null;reconnectTimer=null;reconnectAttempt=0;disposed=!1;socketFactory=e=>new WebSocket(e);url=Ze();events$;_setSocketFactory(e){this.socketFactory=e}_setUrl(e){this.url=e}constructor(){this.mode!=="live"?this.events$=O:this.events$=new te(e=>{!this.socket&&!this.disposed&&this.connect();let t=this.subject.subscribe(e);return()=>t.unsubscribe()}).pipe(ne({resetOnRefCountZero:!1})),this.destroyRef.onDestroy(()=>this.disconnect())}disconnect(){if(!this.disposed){if(this.disposed=!0,this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.socket){try{this.socket.close(1e3,"client disconnect")}catch{}this.socket=null}this.subject.complete()}}ngOnDestroy(){this.disconnect()}connect(){if(this.disposed)return;let e;try{e=this.socketFactory(this.url)}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(u.socketError(n)),this.scheduleReconnect();return}this.socket=e,e.onopen=()=>{this.reconnectAttempt=0,console.info(u.connected(this.url))},e.onmessage=t=>{this.handleFrame(t.data)},e.onerror=t=>{let n=typeof t=="object"&&t!==null&&"message"in t?String(t.message??"unknown"):"unknown";console.warn(u.socketError(n))},e.onclose=t=>{console.info(u.closed(t.code,t.reason)),this.socket=null,!this.disposed&&(Ye.has(t.code)||this.scheduleReconnect())}}handleFrame(e){if(typeof e!="string"){console.warn(u.malformedFrame("non-string frame"));return}let t;try{t=JSON.parse(e)}catch(n){let i=n instanceof Error?n.message:String(n);console.warn(u.malformedFrame(i));return}if(!De(t)){console.warn(u.malformedFrame("envelope shape"));return}this.subject.next(t)}scheduleReconnect(){if(this.disposed)return;if(this.reconnectAttempt>=ee){console.warn(u.reconnectGiveUp(ee)),this.subject.error(new Error(u.reconnectGiveUp(ee)));return}let e=Math.min(this.reconnectAttempt,Fe.length-1),t=Fe[e];this.reconnectAttempt+=1,console.info(u.reconnectScheduled(t,this.reconnectAttempt)),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},t)}get _reconnectAttempt(){return this.reconnectAttempt}static \u0275fac=function(t){return new(t||r)};static \u0275prov=k({token:r,factory:r.\u0275fac,providedIn:"root"})};function V(r){let e=new TextEncoder().encode(r),t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var h="/api",G=class r{http;ws;kindRegistry;constructor(e,t,n){this.http=e??s(R),this.ws=t??s(w),this.kindRegistry=n??s(I)}async health(){return this.getJson(`${h}/health`)}async loadScan(){let[e]=await Promise.all([this.getJson(`${h}/scan`),this.listNodes({limit:0}).catch(()=>null)]);return e}async listNodes(e={}){let t=et(e),n=await this.getJson(`${h}/nodes${t}`);return this.ingestRegistry(n.kindRegistry),n}async getNode(e,t={}){let n=V(e),i=t.includeBody?"?include=body":"";try{let o=await this.getJson(`${h}/nodes/${n}${i}`);return this.ingestRegistry(o.kindRegistry),o}catch(o){if(o instanceof m&&o.code==="not-found")return null;throw o}}async listLinks(e={}){let t=tt(e),n=await this.getJson(`${h}/links${t}`);return this.ingestRegistry(n.kindRegistry),n}async listIssues(e={}){let t=rt(e),n=await this.getJson(`${h}/issues${t}`);return this.ingestRegistry(n.kindRegistry),n}async loadGraph(e="ascii"){let t=`${h}/graph?format=${encodeURIComponent(e)}`;try{return await x(this.http.get(t,{responseType:"text"}))}catch(n){throw this.translateError(n)}}async loadConfig(){let e=await this.getJson(`${h}/config`);return this.ingestRegistry(e.kindRegistry),e.value}async listPlugins(){let e=await this.getJson(`${h}/plugins`);return this.ingestRegistry(e.kindRegistry),e}async setFavorite(e){let t=V(e);try{await x(this.http.put(`${h}/favorites/${t}`,null))}catch(n){throw this.translateError(n)}}async unsetFavorite(e){let t=V(e);try{await x(this.http.delete(`${h}/favorites/${t}`))}catch(n){throw this.translateError(n)}}ingestRegistry(e){e&&this.kindRegistry.ingest(e)}events(){return this.ws.events$}async getJson(e){try{return await x(this.http.get(e))}catch(t){throw this.translateError(t)}}translateError(e){if(e instanceof m)return e;if(e instanceof ue){let n=nt(e.error);return n?new m(n.error.code,n.error.message,n.error.details):new m("internal",e.message||y.errors.malformedResponse)}let t=e instanceof Error?e.message:String(e);return new m("internal",t)}static \u0275fac=function(t){return new(t||r)(F(R),F(w),F(I))};static \u0275prov=k({token:r,factory:r.\u0275fac,providedIn:"root"})};function et(r){let e=new URLSearchParams;r.kind&&r.kind.length>0&&e.set("kind",r.kind.join(",")),r.hasIssues!==void 0&&e.set("hasIssues",String(r.hasIssues)),r.path&&e.set("path",r.path),r.limit!==void 0&&e.set("limit",String(r.limit)),r.offset!==void 0&&e.set("offset",String(r.offset));let t=e.toString();return t?`?${t}`:""}function tt(r){let e=new URLSearchParams;r.kind&&r.kind.length>0&&e.set("kind",r.kind.join(",")),r.from&&e.set("from",r.from),r.to&&e.set("to",r.to);let t=e.toString();return t?`?${t}`:""}function rt(r){let e=new URLSearchParams;r.severity&&e.set("severity",r.severity),r.ruleId&&e.set("ruleId",r.ruleId),r.node&&e.set("node",r.node);let t=e.toString();return t?`?${t}`:""}function nt(r){if(typeof r!="object"||r===null)return null;let e=r;if(e.ok!==!1)return null;let t=e.error;if(typeof t!="object"||t===null)return null;let n=t;return typeof n.code!="string"||typeof n.message!="string"?null:{ok:!1,error:{code:n.code,message:n.message,details:n.details}}}var it="data.json",ot="data.meta.json",J=class{constructor(e=globalThis.fetch.bind(globalThis),t){this.fetchImpl=e;this.kindRegistry=t??s(I)}metaPromise=null;dataPromise=null;kindRegistry;async health(){return(await this.loadMeta()).health}async loadScan(){let[e,t]=await Promise.all([this.loadData(),this.loadMeta()]);return this.kindRegistry.ingest(t.nodes.kindRegistry),e}async listNodes(e={}){let t=await this.loadMeta();if(st(e))return this.kindRegistry.ingest(t.nodes.kindRegistry),t.nodes;let n=await this.loadData(),i=n.issues,o=n.nodes;if(e.kind&&e.kind.length>0){let S=new Set(e.kind);o=o.filter(P=>S.has(P.kind))}if(e.path){let S=ct(e.path);o=o.filter(P=>S.test(P.path))}if(e.hasIssues===!0){let S=Ne(i);o=o.filter(P=>S.has(P.path))}else if(e.hasIssues===!1){let S=Ne(i);o=o.filter(P=>!S.has(P.path))}let g=o.length,b=e.offset??0,M=e.limit??1e3,f=o.slice(b,b+M);return this.kindRegistry.ingest(t.nodes.kindRegistry),{schemaVersion:"1",kind:"nodes",items:f,filters:{kind:e.kind??null,hasIssues:e.hasIssues??null,path:e.path?[e.path]:null},counts:{total:g,returned:f.length,page:{offset:b,limit:M}},kindRegistry:t.nodes.kindRegistry}}async getNode(e,t={}){let[n,i]=await Promise.all([this.loadData(),this.loadMeta()]),o=n.nodes.find(f=>f.path===e);if(!o)return null;let g=n.links.filter(f=>f.target===e),b=n.links.filter(f=>f.source===e),M=n.issues.filter(f=>f.nodeIds.includes(e));return this.kindRegistry.ingest(i.nodes.kindRegistry),{schemaVersion:"1",kind:"node",item:o,links:{incoming:g,outgoing:b},issues:M,kindRegistry:i.nodes.kindRegistry}}async listLinks(e={}){let t=await this.loadMeta();if(at(e))return this.kindRegistry.ingest(t.links.kindRegistry),t.links;let i=(await this.loadData()).links;if(e.kind&&e.kind.length>0){let o=new Set(e.kind);i=i.filter(g=>o.has(g.kind))}return e.from&&(i=i.filter(o=>o.source===e.from)),e.to&&(i=i.filter(o=>o.target===e.to)),this.kindRegistry.ingest(t.links.kindRegistry),{schemaVersion:"1",kind:"links",items:i,filters:{kind:e.kind??null,from:e.from??null,to:e.to??null},counts:{total:i.length,returned:i.length},kindRegistry:t.links.kindRegistry}}async listIssues(e={}){let t=await this.loadMeta();if(lt(e))return this.kindRegistry.ingest(t.issues.kindRegistry),t.issues;let i=(await this.loadData()).issues;return e.severity&&(i=i.filter(o=>o.severity===e.severity)),e.ruleId&&(i=i.filter(o=>o.ruleId===e.ruleId)),e.node&&(i=i.filter(o=>o.nodeIds.includes(e.node))),this.kindRegistry.ingest(t.issues.kindRegistry),{schemaVersion:"1",kind:"issues",items:i,filters:{severity:e.severity??null,ruleId:e.ruleId??null,node:e.node??null},counts:{total:i.length,returned:i.length},kindRegistry:t.issues.kindRegistry}}async loadGraph(e="ascii"){if(e!=="ascii")throw new m("bad-query",y.errors.graphFormatNotInDemo(e));return(await this.loadMeta()).graph.ascii}async loadConfig(){let e=await this.loadMeta();return this.kindRegistry.ingest(e.config.kindRegistry),e.config.value}async listPlugins(){let e=await this.loadMeta();return this.kindRegistry.ingest(e.plugins.kindRegistry),e.plugins}async setFavorite(e){throw new m("demo-readonly","Favorites are not available in demo mode (static bundle is immutable).")}async unsetFavorite(e){throw new m("demo-readonly","Favorites are not available in demo mode (static bundle is immutable).")}events(){return O}loadMeta(){return this.metaPromise||(this.metaPromise=this.fetchJson(ot)),this.metaPromise}loadData(){return this.dataPromise||(this.dataPromise=this.fetchJson(it)),this.dataPromise}async fetchJson(e){let t;try{t=await this.fetchImpl(e)}catch(n){let i=n instanceof Error?n.message:String(n);throw new m("internal",y.errors.demoFetchFailed(e,i))}if(!t.ok)throw new m("internal",y.errors.demoFetchFailed(e,`HTTP ${t.status}`));try{return await t.json()}catch(n){let i=n instanceof Error?n.message:String(n);throw new m("internal",y.errors.demoParseFailed(e,i))}}};function st(r){return!(r.kind&&r.kind.length>0||r.hasIssues!==void 0||r.path||r.offset!==void 0&&r.offset!==0||r.limit!==void 0)}function at(r){return!(r.kind&&r.kind.length>0||r.from||r.to)}function lt(r){return!(r.severity||r.ruleId||r.node)}function Ne(r){let e=new Set;for(let t of r)for(let n of t.nodeIds)e.add(n);return e}function ct(r){let t=r.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");return new RegExp(`^${t}$`)}function $e(){let r=s(_);if(r==="live")return new G(s(R),s(w));if(r==="demo")return new J;let e=r;throw new Error(y.errors.unknownMode(String(e)))}var je={providers:[le(),_e(Le,we()),he(ge()),Pe({}),ce(async()=>{let r=s(Se),[{default:e},{definePreset:t}]=await Promise.all([import("./chunk-FWFBO7KA.js"),import("./chunk-UJOZYR5I.js")]),n=t(e,{semantic:{primary:{50:"#F5F3FF",100:"#EDE9FE",200:"#DDD6FE",300:"#C4B5FD",400:"#A78BFA",500:"#8B5CF6",600:"#7C3AED",700:"#6D28D9",800:"#4C1D95",900:"#2E1065",950:"#1E0A4D"}}});r.setThemeConfig({theme:{preset:n,options:{darkModeSelector:".app-dark"}}})}),{provide:_,useFactory:Oe},{provide:Re,useFactory:$e}]};var Ue={brand:"skill-map",nav:{graph:"Graph",list:"List"},actions:{},badge:{nodes:"nodes"},a11y:{viewSwitcher:"View switcher"},viewportWarning:{title:"Looks like you're on a small screen",subtitle:"skill-map is built for desktop",body:"The graph and inspector need room to breathe. Pop this open on a screen at least 768px wide \u2014 see you there."}};var E={toggleToAuto:"Switch to auto theme (follow system)",toggleToLight:"Switch to light theme",toggleToDark:"Switch to dark theme",currentAuto:"Auto theme (follows system)",currentLight:"Light theme",currentDark:"Dark theme"};var Be="search",We="kinds",Ke="stabilities",Qe="hasIssues",He="staleOnly",X=class r{filters=s(Ce);router=s(be);activatedRoute=s(ve);kindRegistry=s(I);destroyRef=s(N);suppressUrlReadback=!1;constructor(){this.applyUrlToFilters(this.currentParams()),this.router.events.pipe(Ae(this.destroyRef)).subscribe(e=>{if(e instanceof fe){if(this.suppressUrlReadback)return;this.applyUrlToFilters(this.currentParams())}}),$(()=>{let e=this.computeQueryParams();this.writeQueryParams(e)})}currentParams(){let e=this.router.parseUrl(this.router.url),t=new URLSearchParams;for(let[n,i]of Object.entries(e.queryParams))Array.isArray(i)?t.set(n,i.join(",")):i!=null&&t.set(n,String(i));return this.activatedRoute,t}applyUrlToFilters(e){let t=e.get(Be)??"";t!==this.filters.searchText()&&this.filters.setSearchText(t);let n=dt(e.get(We),this.kindRegistry.kinds().map(b=>b.name));ze(n,this.filters.selectedKinds())||this.filters.setKinds(n);let i=mt(e.get(Ke));ze(i,this.filters.selectedStabilities())||this.filters.setStabilities(i);let o=e.get(Qe)==="true";o!==this.filters.hasIssuesOnly()&&this.filters.setHasIssuesOnly(o);let g=e.get(He)==="true";g!==this.filters.staleOnly()&&this.filters.setStaleOnly(g)}computeQueryParams(){let e=this.filters.searchText().trim(),t=this.filters.selectedKinds(),n=this.filters.selectedStabilities(),i=this.filters.hasIssuesOnly(),o=this.filters.staleOnly();return{[Be]:e.length>0?e:null,[We]:t.length>0?t.join(","):null,[Ke]:n.length>0?n.join(","):null,[Qe]:i?"true":null,[He]:o?"true":null}}writeQueryParams(e){let t=this.currentParams(),n=new Map(Object.entries(e)),i=!1;for(let[o,g]of n)if((t.get(o)??null)!==g){i=!0;break}i&&(this.suppressUrlReadback=!0,this.router.navigate([],{relativeTo:this.activatedRoute,queryParams:e,queryParamsHandling:"merge",replaceUrl:!0}).finally(()=>{setTimeout(()=>{this.suppressUrlReadback=!1},0)}))}static \u0275fac=function(t){return new(t||r)};static \u0275prov=k({token:r,factory:r.\u0275fac,providedIn:"root"})};function dt(r,e){if(!r)return[];let t=new Set(e);return r.split(",").map(n=>n.trim()).filter(n=>t.has(n))}function mt(r){if(!r)return[];let e=new Set(xe);return r.split(",").map(t=>t.trim()).filter(t=>e.has(t))}function ze(r,e){if(r.length!==e.length)return!1;for(let t=0;t<r.length;t++)if(r[t]!==e[t])return!1;return!0}var Ve="skill-map.ui.theme",pt="app-dark",ut="dark",Ge="(prefers-color-scheme: dark)",Y=class r{doc=s(ae);mode=C(this.readInitial());systemPrefersDark=C(this.readSystemPref());resolved=v(()=>{let e=this.mode();return e==="auto"?this.systemPrefersDark()?"dark":"light":e});constructor(){this.subscribeToSystemPref(),$(()=>{let e=this.resolved()==="dark",t=this.doc.documentElement;t.classList.toggle(pt,e),t.classList.toggle(ut,e);try{this.doc.defaultView?.localStorage.setItem(Ve,this.mode())}catch{}})}toggle(){this.mode.update(e=>e==="auto"?"light":e==="light"?"dark":"auto")}set(e){this.mode.set(e)}readInitial(){try{let e=this.doc.defaultView?.localStorage.getItem(Ve);if(e==="auto"||e==="light"||e==="dark")return e}catch{}return"auto"}readSystemPref(){try{return this.doc.defaultView?.matchMedia(Ge).matches??!1}catch{return!1}}subscribeToSystemPref(){let e=this.doc.defaultView;if(!e||typeof e.matchMedia!="function")return;e.matchMedia(Ge).addEventListener("change",n=>{this.systemPrefersDark.set(n.matches)})}static \u0275fac=function(t){return new(t||r)};static \u0275prov=k({token:r,factory:r.\u0275fac,providedIn:"root"})};var Je={body:"You are viewing a static demo of skill-map's UI. Install it:",installCommand:"npm i -g @skill-map/cli",homeCta:"\u2190 Back to skill-map.dev",homeHref:"/",dismissAria:"Dismiss demo banner"};function ft(r,e){if(r&1){let t=me();l(0,"div",0),A(1,"span",1),l(2,"p",2),d(3),l(4,"code",3),d(5),c()(),l(6,"a",4),d(7),c(),l(8,"p-button",5),K("onClick",function(){oe(t);let i=D();return se(i.dismiss())}),c()()}if(r&2){let t=D();a(3),Q(" ",t.texts.body," "),a(2),p(t.texts.installCommand),a(),T("href",t.texts.homeHref,j),a(),p(t.texts.homeCta),a(),T("ariaLabel",t.texts.dismissAria)("text",!0)("rounded",!0)}}var Xe="sm.demoBannerDismissed",Z=class r{mode=s(_);texts=Je;dismissed=C(this.readDismissed());visible=v(()=>this.mode==="demo"&&!this.dismissed());dismiss(){this.dismissed.set(!0);try{globalThis.localStorage?.setItem(Xe,"1")}catch{}}readDismissed(){if(this.mode!=="demo")return!0;try{return globalThis.localStorage?.getItem(Xe)==="1"}catch{return!1}}static \u0275fac=function(t){return new(t||r)};static \u0275cmp=U({type:r,selectors:[["sm-demo-banner"]],decls:1,vars:1,consts:[["role","status","data-testid","demo-banner",1,"demo-banner"],["aria-hidden","true",1,"demo-banner__icon","pi","pi-info-circle"],[1,"demo-banner__body"],["data-testid","demo-banner-install",1,"demo-banner__cmd"],["data-testid","demo-banner-home",1,"demo-banner__home",3,"href"],["icon","pi pi-times","severity","secondary","size","small","data-testid","demo-banner-dismiss",3,"onClick","ariaLabel","text","rounded"]],template:function(t,n){t&1&&B(0,ft,9,7,"div",0),t&2&&W(n.visible()?0:-1)},dependencies:[z,H],styles:["[_nghost-%COMP%]{display:block}.demo-banner[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem;border-bottom:1px solid var(--p-content-border-color);background:var(--p-highlight-background);color:var(--p-text-color);font-size:.875rem}.demo-banner__icon[_ngcontent-%COMP%]{font-size:1.1rem;color:var(--p-primary-color)}.demo-banner__body[_ngcontent-%COMP%]{flex:1 1 auto;margin:0;line-height:1.4}.demo-banner__cmd[_ngcontent-%COMP%]{font-family:var(--font-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);background:var(--p-content-background);border:1px solid var(--p-content-border-color);border-radius:.25rem;padding:.05rem .4rem;font-size:.85em;margin-left:.25rem}.demo-banner__home[_ngcontent-%COMP%]{color:var(--p-primary-color);font-weight:500;text-decoration:none;white-space:nowrap}.demo-banner__home[_ngcontent-%COMP%]:hover, .demo-banner__home[_ngcontent-%COMP%]:focus-visible{text-decoration:underline}"],changeDetection:0})};function vt(r,e){if(r&1&&(l(0,"p",10),d(1),c()),r&2){let t=D();a(),p(t.rootLabel())}}var q=class r{loader=s(Me);theme=s(Y);_filterUrlSync=s(X);texts=Ue;count=this.loader.count;rootLabel=v(()=>{let e=this.loader.scan()?.roots??[];if(e.length===0)return"";let t=e[0].replace(/[\\/]+$/,"");if(!t||t===".")return"";let n=t.split(/[\\/]/);return n[n.length-1]??""});themeMode=this.theme.mode;markSrc=v(()=>this.theme.resolved()==="dark"?"skill-map-mark-light.svg":"skill-map-mark-dark.svg");themeIcon=v(()=>{switch(this.themeMode()){case"auto":return"pi pi-desktop";case"light":return"pi pi-sun";case"dark":return"pi pi-moon"}});themeLabel=v(()=>{switch(this.themeMode()){case"auto":return E.toggleToLight;case"light":return E.toggleToDark;case"dark":return E.toggleToAuto}});themeTooltip=v(()=>{switch(this.themeMode()){case"auto":return E.currentAuto;case"light":return E.currentLight;case"dark":return E.currentDark}});ngOnInit(){this.loader.load()}toggleTheme(){this.theme.toggle()}static \u0275fac=function(t){return new(t||r)};static \u0275cmp=U({type:r,selectors:[["app-root"]],decls:31,vars:16,consts:[["role","alert","data-testid","viewport-warning",1,"viewport-warning"],[1,"viewport-warning__card"],["aria-hidden","true",1,"pi","pi-desktop","viewport-warning__icon"],[1,"viewport-warning__title"],[1,"viewport-warning__subtitle"],[1,"viewport-warning__body"],["data-testid","shell",1,"shell"],["data-testid","shell-topbar",1,"shell__topbar"],[1,"shell__brand"],["alt","","aria-hidden","true",1,"shell__brand-mark",3,"src"],[1,"shell__tag"],["data-testid","shell-nav",1,"shell__nav"],["routerLink","/graph","routerLinkActive","is-active","data-testid","nav-graph"],["routerLink","/list","routerLinkActive","is-active","data-testid","nav-list"],[1,"shell__actions"],["severity","secondary","size","small","data-testid","action-theme-toggle",3,"onClick","icon","ariaLabel","pTooltip","text","rounded"],["aria-live","polite","data-testid","shell-nodes-badge",1,"shell__badge"],[1,"shell__main"]],template:function(t,n){t&1&&(l(0,"div",0)(1,"div",1),A(2,"i",2),l(3,"h2",3),d(4),c(),l(5,"p",4),d(6),c(),l(7,"p",5),d(8),c()()(),l(9,"div",6),A(10,"sm-demo-banner"),l(11,"header",7)(12,"div",8),A(13,"img",9),l(14,"div")(15,"h1"),d(16),c(),B(17,vt,2,1,"p",10),c()(),l(18,"nav",11)(19,"a",12),d(20),c(),l(21,"a",13),d(22),c()(),l(23,"div",14)(24,"p-button",15),K("onClick",function(){return n.toggleTheme()}),c(),l(25,"div",16)(26,"strong"),d(27),c(),d(28),c()()(),l(29,"main",17),A(30,"router-outlet"),c()()),t&2&&(a(4),p(n.texts.viewportWarning.title),a(2),p(n.texts.viewportWarning.subtitle),a(2),p(n.texts.viewportWarning.body),a(5),T("src",n.markSrc(),j),a(3),p(n.texts.brand),a(),W(n.rootLabel()?17:-1),a(),de("aria-label",n.texts.a11y.viewSwitcher),a(2),p(n.texts.nav.graph),a(2),p(n.texts.nav.list),a(2),T("icon",n.themeIcon())("ariaLabel",n.themeLabel())("pTooltip",n.themeTooltip())("text",!0)("rounded",!0),a(3),p(n.count()),a(),Q(" ",n.texts.badge.nodes," "))},dependencies:[ye,ke,Ie,z,H,Te,Ee,Z],styles:["[_nghost-%COMP%]{display:block;height:100dvh;--shell-topbar-bg: #FFFFFF;--shell-topbar-border: var(--sm-violet-100);--shell-topbar-text: var(--sm-violet-800);--shell-topbar-text-strong: var(--sm-violet-900);--shell-topbar-text-muted: var(--sm-violet-600);--shell-topbar-hover-bg: color-mix(in srgb, var(--sm-violet-500) 10%, transparent);--shell-topbar-active-bg: var(--sm-violet-100);--shell-topbar-active-text: var(--sm-violet-800);--shell-topbar-badge-bg: var(--sm-violet-100)}.app-dark[_nghost-%COMP%], .app-dark [_nghost-%COMP%]{--shell-topbar-bg: #1A1B22;--shell-topbar-border: color-mix(in srgb, var(--sm-violet-300) 8%, transparent);--shell-topbar-text: var(--sm-violet-100);--shell-topbar-text-strong: var(--sm-violet-100);--shell-topbar-text-muted: var(--sm-violet-300);--shell-topbar-hover-bg: color-mix(in srgb, var(--sm-violet-400) 12%, transparent);--shell-topbar-active-bg: color-mix(in srgb, var(--sm-violet-500) 22%, transparent);--shell-topbar-active-text: var(--sm-violet-100);--shell-topbar-badge-bg: color-mix(in srgb, var(--sm-violet-500) 14%, transparent)}.shell[_ngcontent-%COMP%]{display:flex;flex-direction:column;height:100dvh}.shell__topbar[_ngcontent-%COMP%]{display:flex;align-items:center;gap:2rem;padding:.75rem 1.5rem;background:var(--shell-topbar-bg);border-bottom:1px solid var(--shell-topbar-border);color:var(--shell-topbar-text)}.shell__brand[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.75rem}.shell__brand-mark[_ngcontent-%COMP%]{width:2rem;height:2rem;display:block}.shell__brand[_ngcontent-%COMP%] h1[_ngcontent-%COMP%]{margin:0;font-size:1.05rem;font-weight:600;letter-spacing:-.01em;color:var(--shell-topbar-text-strong)}.shell__tag[_ngcontent-%COMP%]{margin:0;font-size:.72rem;color:var(--shell-topbar-text-muted);letter-spacing:.02em;text-transform:uppercase}.shell__nav[_ngcontent-%COMP%]{display:flex;gap:.25rem;margin-left:auto}.shell__nav[_ngcontent-%COMP%] a[_ngcontent-%COMP%]{padding:.5rem .9rem;border-radius:.5rem;font-size:.9rem;font-weight:500;color:var(--shell-topbar-text-muted);transition:background .15s ease,color .15s ease}.shell__nav[_ngcontent-%COMP%] a[_ngcontent-%COMP%]:hover{background:var(--shell-topbar-hover-bg);color:var(--shell-topbar-text-strong)}.shell__nav[_ngcontent-%COMP%] a.is-active[_ngcontent-%COMP%]{background:var(--shell-topbar-active-bg);color:var(--shell-topbar-active-text)}.shell__actions[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.75rem}.shell__badge[_ngcontent-%COMP%]{padding:.4rem .8rem;border-radius:999px;background:var(--shell-topbar-badge-bg);color:var(--shell-topbar-text-muted);font-size:.85rem}.shell__badge[_ngcontent-%COMP%] strong[_ngcontent-%COMP%]{color:var(--shell-topbar-text-strong);margin-right:.25rem}.shell__main[_ngcontent-%COMP%]{flex:1;min-height:0;overflow-y:auto;width:100%}@media(max-width:1280px){.shell__topbar[_ngcontent-%COMP%]{gap:1rem;padding:.5rem 1rem}.shell__tag[_ngcontent-%COMP%]{display:none}.shell__nav[_ngcontent-%COMP%] a[_ngcontent-%COMP%]{padding:.4rem .7rem;font-size:.85rem}}.viewport-warning[_ngcontent-%COMP%]{display:none}@media(max-width:767px){.viewport-warning[_ngcontent-%COMP%]{position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;padding:1.5rem;background:var(--sm-bg-content)}.viewport-warning__card[_ngcontent-%COMP%]{display:flex;flex-direction:column;align-items:center;text-align:center;gap:.85rem;max-width:22rem}.viewport-warning__icon[_ngcontent-%COMP%]{font-size:3rem;color:var(--p-primary-color);margin-bottom:.25rem}.viewport-warning__title[_ngcontent-%COMP%]{margin:0;font-size:1.35rem;font-weight:700;color:var(--p-text-color);line-height:1.25}.viewport-warning__subtitle[_ngcontent-%COMP%]{margin:0;font-size:1rem;font-weight:500;color:var(--p-primary-color);line-height:1.35}.viewport-warning__body[_ngcontent-%COMP%]{margin:0;color:var(--p-text-muted-color);line-height:1.5;font-size:.9rem}.shell[_ngcontent-%COMP%]{display:none}}"],changeDetection:0})};pe(q,je).catch(r=>console.error(r));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- Step 9.6.2 — kernel sidecar reader + drift detection.
|
|
2
|
+
--
|
|
3
|
+
-- Extends `scan_nodes` with three new columns to denormalise the
|
|
4
|
+
-- sidecar-derived state for fast queries:
|
|
5
|
+
--
|
|
6
|
+
-- - `sidecar_present` — boolean flag, 1 when a co-located `.sm` file
|
|
7
|
+
-- accompanies this node, 0 otherwise. Default 0.
|
|
8
|
+
-- - `sidecar_status` — fresh / stale-body / stale-frontmatter /
|
|
9
|
+
-- stale-both. NULL when no sidecar is present.
|
|
10
|
+
-- - `annotations_json` — JSON-encoded `annotations:` block from the
|
|
11
|
+
-- parsed sidecar (the typed surface declared by
|
|
12
|
+
-- `spec/schemas/annotations.schema.json`). NULL when no sidecar or
|
|
13
|
+
-- when the block is empty.
|
|
14
|
+
--
|
|
15
|
+
-- Hard-cut migration of the source-of-truth for three pre-existing
|
|
16
|
+
-- columns (Decision #3 — option (a), extend `scan_nodes`):
|
|
17
|
+
--
|
|
18
|
+
-- - `stability` — was sourced from `frontmatter.metadata.stability`,
|
|
19
|
+
-- now sourced from sidecar `annotations.stability`.
|
|
20
|
+
-- - `version` — was `TEXT` (semver string from
|
|
21
|
+
-- `frontmatter.metadata.version`); now `INTEGER` (monotonic counter
|
|
22
|
+
-- from sidecar `annotations.version`). Pre-9.6.2 rows reset to
|
|
23
|
+
-- NULL — greenfield migration, no automatic semver→integer
|
|
24
|
+
-- conversion (Decision #125 / per-project policy).
|
|
25
|
+
-- - `author` — was sourced from `frontmatter.author`, now sourced
|
|
26
|
+
-- from sidecar `annotations.author`.
|
|
27
|
+
--
|
|
28
|
+
-- The fallback path through `pickMetadata` for these three fields is
|
|
29
|
+
-- removed in the kernel; other consumers of `metadata.*` (e.g.
|
|
30
|
+
-- broken-ref's `metadata.related`) are out of scope for 9.6.2.
|
|
31
|
+
--
|
|
32
|
+
-- SQLite limitation note: the three pre-existing columns retain their
|
|
33
|
+
-- original types where possible. For `version` we change the type by
|
|
34
|
+
-- dropping and re-adding the column (safe: greenfield reset to NULL
|
|
35
|
+
-- is the documented migration outcome). DROP COLUMN requires SQLite
|
|
36
|
+
-- 3.35+; node:sqlite (Node 22+) ships SQLite ≥ 3.45.
|
|
37
|
+
|
|
38
|
+
ALTER TABLE scan_nodes DROP COLUMN version;
|
|
39
|
+
ALTER TABLE scan_nodes ADD COLUMN version INTEGER;
|
|
40
|
+
|
|
41
|
+
ALTER TABLE scan_nodes ADD COLUMN sidecar_present INTEGER NOT NULL DEFAULT 0;
|
|
42
|
+
ALTER TABLE scan_nodes ADD COLUMN sidecar_status TEXT;
|
|
43
|
+
ALTER TABLE scan_nodes ADD COLUMN annotations_json TEXT;
|
|
44
|
+
|
|
45
|
+
-- Reset stability + author to NULL — they used to be populated from
|
|
46
|
+
-- frontmatter.metadata.{stability,author}; the new source is
|
|
47
|
+
-- sidecar `annotations.{stability,author}` and a re-scan repopulates.
|
|
48
|
+
UPDATE scan_nodes SET stability = NULL, author = NULL;
|
|
49
|
+
|
|
50
|
+
-- Constraint mirrors the four legal values returned by the kernel's
|
|
51
|
+
-- drift detector. NULL is allowed (and required) when no sidecar is
|
|
52
|
+
-- present.
|
|
53
|
+
CREATE INDEX ix_scan_nodes_sidecar_status ON scan_nodes(sidecar_status);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- Step 9.6 catalog-curation follow-up (2026-05-07).
|
|
2
|
+
--
|
|
3
|
+
-- Drop the vestigial `scan_nodes.author` column. The 9.6.2 migration
|
|
4
|
+
-- denormalised `annotations.author` into the column; the 2026-05-07
|
|
5
|
+
-- catalog curation removed `author` from `annotations.schema.json`,
|
|
6
|
+
-- which left the column without a canonical source. Anyone who still
|
|
7
|
+
-- writes `author:` in their `.sm` rides on `additionalProperties: true`
|
|
8
|
+
-- — the value lands in `annotations_json` (no longer in a typed
|
|
9
|
+
-- column), and `unknown-field` warns on it as a typo guard.
|
|
10
|
+
--
|
|
11
|
+
-- Greenfield drop: pre-9.6 rows had the column reset to NULL by
|
|
12
|
+
-- migration 002, and the curation rolled out before any released
|
|
13
|
+
-- consumer pinned the post-9.6.2 shape. No automatic salvage path —
|
|
14
|
+
-- if a deployed DB carried real data, it is preserved verbatim under
|
|
15
|
+
-- `scan_nodes.annotations_json` until the next scan rewrites the row.
|
|
16
|
+
--
|
|
17
|
+
-- DROP COLUMN requires SQLite 3.35+; node:sqlite (Node 22+) ships
|
|
18
|
+
-- SQLite ≥ 3.45.
|
|
19
|
+
|
|
20
|
+
ALTER TABLE scan_nodes DROP COLUMN author;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
-- R15 closure (2026-05-07) — surface the full parsed `.sm` root on the
|
|
2
|
+
-- BFF wire shape (`Node.sidecar.root`).
|
|
3
|
+
--
|
|
4
|
+
-- Adds `scan_nodes.sidecar_root_json`, sibling to `annotations_json`
|
|
5
|
+
-- (Decision: option (b), additive — no rewrite of the existing read
|
|
6
|
+
-- path; duplicates the `annotations:` sub-block by design so
|
|
7
|
+
-- pre-R15 consumers reading `annotations_json` keep working unchanged).
|
|
8
|
+
--
|
|
9
|
+
-- Column shape:
|
|
10
|
+
-- - JSON-encoded full parsed YAML root of the matching `.sm` file
|
|
11
|
+
-- (every top-level reserved block — `for` / `annotations` /
|
|
12
|
+
-- `settings` / `audit` — plus `<plugin-id>:` namespaces a plugin
|
|
13
|
+
-- opt-in to root via `annotationContributions`).
|
|
14
|
+
-- - NULL when no sidecar accompanies the node, or when the sidecar
|
|
15
|
+
-- exists but failed to parse / validate (in that case
|
|
16
|
+
-- `sidecar_present` stays 1 and `sidecar_status` stays NULL).
|
|
17
|
+
--
|
|
18
|
+
-- Backfill on existing rows: NULL. Re-scan repopulates the column from
|
|
19
|
+
-- the live `.sm` file via `parseSidecar()`'s already-computed `raw`
|
|
20
|
+
-- payload. Greenfield posture per `feedback_greenfield_no_versioning.md`
|
|
21
|
+
-- — no released consumer depends on the prior shape.
|
|
22
|
+
|
|
23
|
+
ALTER TABLE scan_nodes ADD COLUMN sidecar_root_json TEXT;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- Per-node "favorite" flag persisted per user (single-user local DB).
|
|
2
|
+
--
|
|
3
|
+
-- Zone `state_` because favorites are user-authored preference and must
|
|
4
|
+
-- survive `sm scan` truncation and `sm db reset` (which drops only
|
|
5
|
+
-- `scan_*`). Absence of a row means "not favorited".
|
|
6
|
+
--
|
|
7
|
+
-- `node_path` is FK-semantic to `scan_nodes.path`. The rename heuristic
|
|
8
|
+
-- (`migrateNodeFks` in src/kernel/adapters/sqlite/history.ts) MUST migrate
|
|
9
|
+
-- rows here when a path is renamed, same protocol as the other state_*
|
|
10
|
+
-- tables. Simple PK update — no composite key, no collision shape.
|
|
11
|
+
--
|
|
12
|
+
-- The BFF's `/api/nodes` route loads the full set of paths once per
|
|
13
|
+
-- request (typical favorite count is small) and decorates the in-memory
|
|
14
|
+
-- node list with a derived `isFavorite` boolean by Set membership. No
|
|
15
|
+
-- SQL JOIN against `scan_nodes` is required.
|
|
16
|
+
|
|
17
|
+
CREATE TABLE state_node_favorites (
|
|
18
|
+
node_path TEXT PRIMARY KEY,
|
|
19
|
+
favorited_at INTEGER NOT NULL
|
|
20
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skill-map/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "skill-map reference implementation — kernel + CLI + adapters.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -58,15 +58,15 @@
|
|
|
58
58
|
"pretest:ci": "tsup",
|
|
59
59
|
"pretest:coverage": "tsup",
|
|
60
60
|
"pretest:coverage:html": "tsup",
|
|
61
|
-
"test": "tsc --noEmit && node --import tsx --test --test-reporter=spec 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts'",
|
|
62
|
-
"test:ci": "tsc --noEmit && node --import tsx --test 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts'",
|
|
63
|
-
"test:coverage": "tsc --noEmit && SKILL_MAP_SKIP_BENCHMARK=1 node --experimental-default-config-file --import tsx --test --experimental-test-coverage 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts'",
|
|
64
|
-
"test:coverage:html": "tsc --noEmit && SKILL_MAP_SKIP_BENCHMARK=1 c8 node --import tsx --test 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts'",
|
|
61
|
+
"test": "tsc --noEmit && node --import tsx --test --test-reporter=spec 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts' 'server/**/*.test.ts'",
|
|
62
|
+
"test:ci": "tsc --noEmit && node --import tsx --test 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts' 'server/**/*.test.ts'",
|
|
63
|
+
"test:coverage": "tsc --noEmit && SKILL_MAP_SKIP_BENCHMARK=1 node --experimental-default-config-file --import tsx --test --experimental-test-coverage 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts' 'server/**/*.test.ts'",
|
|
64
|
+
"test:coverage:html": "tsc --noEmit && SKILL_MAP_SKIP_BENCHMARK=1 c8 node --import tsx --test 'test/**/*.test.ts' 'built-in-plugins/**/*.test.ts' 'kernel/**/*.test.ts' 'server/**/*.test.ts'",
|
|
65
65
|
"clean": "rm -rf dist coverage"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@hono/node-server": "2.0.1",
|
|
69
|
-
"@skill-map/spec": "0.
|
|
69
|
+
"@skill-map/spec": "0.18.0",
|
|
70
70
|
"ajv": "8.18.0",
|
|
71
71
|
"ajv-formats": "3.0.1",
|
|
72
72
|
"chokidar": "5.0.0",
|