@i4ctime/q-ring 0.16.1 → 0.17.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/README.md +26 -6
- package/dist/{chunk-NCM5GHNW.js → chunk-KFILBHOY.js} +58 -7
- package/dist/chunk-KFILBHOY.js.map +1 -0
- package/dist/{chunk-5LFKBZ3Q.js → chunk-SQKTDYSO.js} +80 -7
- package/dist/chunk-SQKTDYSO.js.map +1 -0
- package/dist/dashboard-2MLSJZQR.js +658 -0
- package/dist/dashboard-2MLSJZQR.js.map +1 -0
- package/dist/dashboard-WVPR5BQO.js +658 -0
- package/dist/dashboard-WVPR5BQO.js.map +1 -0
- package/dist/index.js +96 -27
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +181 -161
- package/dist/mcp.js.map +1 -1
- package/package.json +14 -13
- package/dist/chunk-5LFKBZ3Q.js.map +0 -1
- package/dist/chunk-NCM5GHNW.js.map +0 -1
- package/dist/dashboard-A3GJQCJX.js +0 -658
- package/dist/dashboard-A3GJQCJX.js.map +0 -1
- package/dist/dashboard-R3FWTFFW.js +0 -658
- package/dist/dashboard-R3FWTFFW.js.map +0 -1
|
@@ -1,658 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
PACKAGE_VERSION,
|
|
4
|
-
checkDecay,
|
|
5
|
-
collapseEnvironment,
|
|
6
|
-
detectAnomalies,
|
|
7
|
-
getPolicySummary,
|
|
8
|
-
listApprovals,
|
|
9
|
-
listEntanglements,
|
|
10
|
-
listHooks,
|
|
11
|
-
listMemory,
|
|
12
|
-
listSecrets,
|
|
13
|
-
queryAudit,
|
|
14
|
-
readProjectConfig,
|
|
15
|
-
tunnelList,
|
|
16
|
-
verifyAuditChain
|
|
17
|
-
} from "./chunk-5LFKBZ3Q.js";
|
|
18
|
-
|
|
19
|
-
// src/core/dashboard.ts
|
|
20
|
-
import { createServer } from "http";
|
|
21
|
-
import { randomBytes, timingSafeEqual } from "crypto";
|
|
22
|
-
|
|
23
|
-
// src/core/dashboard-client.ts
|
|
24
|
-
var DASHBOARD_CLIENT = '"use strict";(()=>{var J,b,we,tt,q,ge,Ce,Me,se,W,I,Se,ie,ae,oe,nt,O={},Y=[],st=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Q=Array.isArray;function T(t,e){for(var n in e)t[n]=e[n];return t}function le(t){t&&t.parentNode&&t.parentNode.removeChild(t)}function re(t,e,n){var s,o,a,l={};for(a in e)a=="key"?s=e[a]:a=="ref"?o=e[a]:l[a]=e[a];if(arguments.length>2&&(l.children=arguments.length>3?J.call(arguments,2):n),typeof t=="function"&&t.defaultProps!=null)for(a in t.defaultProps)l[a]===void 0&&(l[a]=t.defaultProps[a]);return K(t,l,s,o,null)}function K(t,e,n,s,o){var a={type:t,props:e,key:n,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o==null?++we:o,__i:-1,__u:0};return o==null&&b.vnode!=null&&b.vnode(a),a}function X(t){return t.children}function z(t,e){this.props=t,this.context=e}function j(t,e){if(e==null)return t.__?j(t.__,t.__i+1):null;for(var n;e<t.__k.length;e++)if((n=t.__k[e])!=null&&n.__e!=null)return n.__e;return typeof t.type=="function"?j(t):null}function at(t){if(t.__P&&t.__d){var e=t.__v,n=e.__e,s=[],o=[],a=T({},e);a.__v=e.__v+1,b.vnode&&b.vnode(a),ce(t.__P,a,e,t.__n,t.__P.namespaceURI,32&e.__u?[n]:null,s,n==null?j(e):n,!!(32&e.__u),o),a.__v=e.__v,a.__.__k[a.__i]=a,Te(s,a,o),e.__e=e.__=null,a.__e!=n&&Ae(a)}}function Ae(t){if((t=t.__)!=null&&t.__c!=null)return t.__e=t.__c.base=null,t.__k.some(function(e){if(e!=null&&e.__e!=null)return t.__e=t.__c.base=e.__e}),Ae(t)}function ke(t){(!t.__d&&(t.__d=!0)&&q.push(t)&&!G.__r++||ge!=b.debounceRendering)&&((ge=b.debounceRendering)||Ce)(G)}function G(){try{for(var t,e=1;q.length;)q.length>e&&q.sort(Me),t=q.shift(),e=q.length,at(t)}finally{q.length=G.__r=0}}function Ee(t,e,n,s,o,a,l,u,_,c,r){var p,i,v,f,h,y,m,$=s&&s.__k||Y,g=e.length;for(_=ot(n,e,$,_,g),p=0;p<g;p++)(v=n.__k[p])!=null&&(i=v.__i!=-1&&$[v.__i]||O,v.__i=p,y=ce(t,v,i,o,a,l,u,_,c,r),f=v.__e,v.ref&&i.ref!=v.ref&&(i.ref&&de(i.ref,null,v),r.push(v.ref,v.__c||f,v)),h==null&&f!=null&&(h=f),(m=!!(4&v.__u))||i.__k===v.__k?(_=Pe(v,_,t,m),m&&i.__e&&(i.__e=null)):typeof v.type=="function"&&y!==void 0?_=y:f&&(_=f.nextSibling),v.__u&=-7);return n.__e=h,_}function ot(t,e,n,s,o){var a,l,u,_,c,r=n.length,p=r,i=0;for(t.__k=new Array(o),a=0;a<o;a++)(l=e[a])!=null&&typeof l!="boolean"&&typeof l!="function"?(typeof l=="string"||typeof l=="number"||typeof l=="bigint"||l.constructor==String?l=t.__k[a]=K(null,l,null,null,null):Q(l)?l=t.__k[a]=K(X,{children:l},null,null,null):l.constructor===void 0&&l.__b>0?l=t.__k[a]=K(l.type,l.props,l.key,l.ref?l.ref:null,l.__v):t.__k[a]=l,_=a+i,l.__=t,l.__b=t.__b+1,u=null,(c=l.__i=it(l,n,_,p))!=-1&&(p--,(u=n[c])&&(u.__u|=2)),u==null||u.__v==null?(c==-1&&(o>r?i--:o<r&&i++),typeof l.type!="function"&&(l.__u|=4)):c!=_&&(c==_-1?i--:c==_+1?i++:(c>_?i--:i++,l.__u|=4))):t.__k[a]=null;if(p)for(a=0;a<r;a++)(u=n[a])!=null&&(2&u.__u)==0&&(u.__e==s&&(s=j(u)),Ne(u,u));return s}function Pe(t,e,n,s){var o,a;if(typeof t.type=="function"){for(o=t.__k,a=0;o&&a<o.length;a++)o[a]&&(o[a].__=t,e=Pe(o[a],e,n,s));return e}t.__e!=e&&(s&&(e&&t.type&&!e.parentNode&&(e=j(t)),n.insertBefore(t.__e,e||null)),e=t.__e);do e=e&&e.nextSibling;while(e!=null&&e.nodeType==8);return e}function it(t,e,n,s){var o,a,l,u=t.key,_=t.type,c=e[n],r=c!=null&&(2&c.__u)==0;if(c===null&&u==null||r&&u==c.key&&_==c.type)return n;if(s>(r?1:0)){for(o=n-1,a=n+1;o>=0||a<e.length;)if((c=e[l=o>=0?o--:a++])!=null&&(2&c.__u)==0&&u==c.key&&_==c.type)return l}return-1}function be(t,e,n){e[0]=="-"?t.setProperty(e,n==null?"":n):t[e]=n==null?"":typeof n!="number"||st.test(e)?n:n+"px"}function V(t,e,n,s,o){var a,l;e:if(e=="style")if(typeof n=="string")t.style.cssText=n;else{if(typeof s=="string"&&(t.style.cssText=s=""),s)for(e in s)n&&e in n||be(t.style,e,"");if(n)for(e in n)s&&n[e]==s[e]||be(t.style,e,n[e])}else if(e[0]=="o"&&e[1]=="n")a=e!=(e=e.replace(Se,"$1")),l=e.toLowerCase(),e=l in t||e=="onFocusOut"||e=="onFocusIn"?l.slice(2):e.slice(2),t.l||(t.l={}),t.l[e+a]=n,n?s?n[I]=s[I]:(n[I]=ie,t.addEventListener(e,a?oe:ae,a)):t.removeEventListener(e,a?oe:ae,a);else{if(o=="http://www.w3.org/2000/svg")e=e.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(e!="width"&&e!="height"&&e!="href"&&e!="list"&&e!="form"&&e!="tabIndex"&&e!="download"&&e!="rowSpan"&&e!="colSpan"&&e!="role"&&e!="popover"&&e in t)try{t[e]=n==null?"":n;break e}catch{}typeof n=="function"||(n==null||n===!1&&e[4]!="-"?t.removeAttribute(e):t.setAttribute(e,e=="popover"&&n==1?"":n))}}function xe(t){return function(e){if(this.l){var n=this.l[e.type+t];if(e[W]==null)e[W]=ie++;else if(e[W]<n[I])return;return n(b.event?b.event(e):e)}}}function ce(t,e,n,s,o,a,l,u,_,c){var r,p,i,v,f,h,y,m,$,g,w,P,H,me,B,ne,R=e.type;if(e.constructor!==void 0)return null;128&n.__u&&(_=!!(32&n.__u),a=[u=e.__e=n.__e]),(r=b.__b)&&r(e);e:if(typeof R=="function"){p=l.length;try{if($=e.props,g=R.prototype&&R.prototype.render,w=(r=R.contextType)&&s[r.__c],P=r?w?w.props.value:r.__:s,n.__c?m=(i=e.__c=n.__c).__=i.__E:(g?e.__c=i=new R($,P):(e.__c=i=new z($,P),i.constructor=R,i.render=rt),w&&w.sub(i),i.state||(i.state={}),i.__n=s,v=i.__d=!0,i.__h=[],i._sb=[]),g&&i.__s==null&&(i.__s=i.state),g&&R.getDerivedStateFromProps!=null&&(i.__s==i.state&&(i.__s=T({},i.__s)),T(i.__s,R.getDerivedStateFromProps($,i.__s))),f=i.props,h=i.state,i.__v=e,v)g&&R.getDerivedStateFromProps==null&&i.componentWillMount!=null&&i.componentWillMount(),g&&i.componentDidMount!=null&&i.__h.push(i.componentDidMount);else{if(g&&R.getDerivedStateFromProps==null&&$!==f&&i.componentWillReceiveProps!=null&&i.componentWillReceiveProps($,P),e.__v==n.__v||!i.__e&&i.shouldComponentUpdate!=null&&i.shouldComponentUpdate($,i.__s,P)===!1){e.__v!=n.__v&&(i.props=$,i.state=i.__s,i.__d=!1),e.__e=n.__e,e.__k=n.__k,e.__k.some(function(D){D&&(D.__=e)}),Y.push.apply(i.__h,i._sb),i._sb=[],i.__h.length&&l.push(i);break e}i.componentWillUpdate!=null&&i.componentWillUpdate($,i.__s,P),g&&i.componentDidUpdate!=null&&i.__h.push(function(){i.componentDidUpdate(f,h,y)})}if(i.context=P,i.props=$,i.__P=t,i.__e=!1,H=b.__r,me=0,g)i.state=i.__s,i.__d=!1,H&&H(e),r=i.render(i.props,i.state,i.context),Y.push.apply(i.__h,i._sb),i._sb=[];else do i.__d=!1,H&&H(e),r=i.render(i.props,i.state,i.context),i.state=i.__s;while(i.__d&&++me<25);i.state=i.__s,i.getChildContext!=null&&(s=T(T({},s),i.getChildContext())),g&&!v&&i.getSnapshotBeforeUpdate!=null&&(y=i.getSnapshotBeforeUpdate(f,h)),B=r!=null&&r.type===X&&r.key==null?qe(r.props.children):r,u=Ee(t,Q(B)?B:[B],e,n,s,o,a,l,u,_,c),i.base=e.__e,e.__u&=-161,i.__h.length&&l.push(i),m&&(i.__E=i.__=null)}catch(D){if(l.length=p,e.__v=null,_||a!=null){if(D.then){for(e.__u|=_?160:128;u&&u.nodeType==8&&u.nextSibling;)u=u.nextSibling;a!=null&&(a[a.indexOf(u)]=null),e.__e=u}else if(a!=null)for(ne=a.length;ne--;)le(a[ne])}else e.__e=n.__e;e.__k==null&&(e.__k=n.__k||[]),D.then||Re(e),b.__e(D,e,n)}}else a==null&&e.__v==n.__v?(e.__k=n.__k,e.__e=n.__e):u=e.__e=lt(n.__e,e,n,s,o,a,l,_,c);return(r=b.diffed)&&r(e),128&e.__u?void 0:u}function Re(t){t&&(t.__c&&(t.__c.__e=!0),t.__k&&t.__k.some(Re))}function Te(t,e,n){for(var s=0;s<n.length;s++)de(n[s],n[++s],n[++s]);b.__c&&b.__c(e,t),t.some(function(o){try{t=o.__h,o.__h=[],t.some(function(a){a.call(o)})}catch(a){b.__e(a,o.__v)}})}function qe(t){return typeof t!="object"||t==null||t.__b>0?t:Q(t)?t.map(qe):t.constructor!==void 0?null:T({},t)}function lt(t,e,n,s,o,a,l,u,_){var c,r,p,i,v,f,h,y=n.props||O,m=e.props,$=e.type;if($=="svg"?o="http://www.w3.org/2000/svg":$=="math"?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),a!=null){for(c=0;c<a.length;c++)if((v=a[c])&&"setAttribute"in v==!!$&&($?v.localName==$:v.nodeType==3)){t=v,a[c]=null;break}}if(t==null){if($==null)return document.createTextNode(m);t=document.createElementNS(o,$,m.is&&m),u&&(b.__m&&b.__m(e,a),u=!1),a=null}if($==null)y===m||u&&t.data==m||(t.data=m);else{if(a=$=="textarea"&&m.defaultValue!=null?null:a&&J.call(t.childNodes),!u&&a!=null)for(y={},c=0;c<t.attributes.length;c++)y[(v=t.attributes[c]).name]=v.value;for(c in y)v=y[c],c=="dangerouslySetInnerHTML"?p=v:c=="children"||c in m||c=="value"&&"defaultValue"in m||c=="checked"&&"defaultChecked"in m||V(t,c,null,v,o);for(c in m)v=m[c],c=="children"?i=v:c=="dangerouslySetInnerHTML"?r=v:c=="value"?f=v:c=="checked"?h=v:u&&typeof v!="function"||y[c]===v||V(t,c,v,y[c],o);if(r)u||p&&(r.__html==p.__html||r.__html==t.innerHTML)||(t.innerHTML=r.__html),e.__k=[];else if(p&&(t.innerHTML=""),Ee(e.type=="template"?t.content:t,Q(i)?i:[i],e,n,s,$=="foreignObject"?"http://www.w3.org/1999/xhtml":o,a,l,a?a[0]:n.__k&&j(n,0),u,_),a!=null)for(c=a.length;c--;)le(a[c]);u&&$!="textarea"||(c="value",$=="progress"&&f==null?t.removeAttribute("value"):f!=null&&(f!==t[c]||$=="progress"&&!f||$=="option"&&f!=y[c])&&V(t,c,f,y[c],o),c="checked",h!=null&&h!=t[c]&&V(t,c,h,y[c],o))}return t}function de(t,e,n){try{if(typeof t=="function"){var s=typeof t.__u=="function";s&&t.__u(),s&&e==null||(t.__u=t(e))}else t.current=e}catch(o){b.__e(o,n)}}function Ne(t,e,n){var s,o;if(b.unmount&&b.unmount(t),(s=t.ref)&&(s.current&&s.current!=t.__e||de(s,null,e)),(s=t.__c)!=null){if(s.componentWillUnmount)try{s.componentWillUnmount()}catch(a){b.__e(a,e)}s.base=s.__P=s.__n=null}if(s=t.__k)for(o=0;o<s.length;o++)s[o]&&Ne(s[o],e,n||typeof t.type!="function");n||le(t.__e),t.__c=t.__=t.__e=void 0}function rt(t,e,n){return this.constructor(t,n)}function He(t,e,n){var s,o,a,l;e==document&&(e=document.documentElement),b.__&&b.__(t,e),o=(s=typeof n=="function")?null:n&&n.__k||e.__k,a=[],l=[],ce(e,t=(!s&&n||e).__k=re(X,null,[t]),o||O,O,e.namespaceURI,!s&&n?[n]:o?null:e.firstChild?J.call(e.childNodes):null,a,!s&&n?n:o?o.__e:e.firstChild,s,l),Te(a,t,l),t.props.children=null}J=Y.slice,b={__e:function(t,e,n,s){for(var o,a,l;e=e.__;)if((o=e.__c)&&!o.__)try{if((a=o.constructor)&&a.getDerivedStateFromError!=null&&(o.setState(a.getDerivedStateFromError(t)),l=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(t,s||{}),l=o.__d),l)return o.__E=o}catch(u){t=u}throw t}},we=0,tt=function(t){return t!=null&&t.constructor===void 0},z.prototype.setState=function(t,e){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=T({},this.state),typeof t=="function"&&(t=t(T({},n),this.props)),t&&T(n,t),t!=null&&this.__v&&(e&&this._sb.push(e),ke(this))},z.prototype.forceUpdate=function(t){this.__v&&(this.__e=!0,t&&this.__h.push(t),ke(this))},z.prototype.render=X,q=[],Ce=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Me=function(t,e){return t.__v.__b-e.__v.__b},G.__r=0,se=Math.random().toString(8),W="__d"+se,I="__a"+se,Se=/(PointerCapture)$|Capture$/i,ie=0,ae=xe(!1),oe=xe(!0),nt=0;var U,x,ue,De,F=0,We=[],C=b,je=C.__b,Le=C.__r,Ie=C.diffed,Ue=C.__c,Fe=C.unmount,Be=C.__;function _e(t,e){C.__h&&C.__h(x,t,F||e),F=0;var n=x.__H||(x.__H={__:[],__h:[]});return t>=n.__.length&&n.__.push({}),n.__[t]}function N(t){return F=1,ct(ze,t)}function ct(t,e,n){var s=_e(U++,2);if(s.t=t,!s.__c&&(s.__=[n?n(e):ze(void 0,e),function(u){var _=s.__N?s.__N[0]:s.__[0],c=s.t(_,u);_!==c&&(s.__N=[c,s.__[1]],s.__c.setState({}))}],s.__c=x,!x.__f)){var o=function(u,_,c){if(!s.__c.__H)return!0;var r=!1,p=s.__c.props!==u;if(s.__c.__H.__.some(function(v){if(v.__N){r=!0;var f=v.__[0];v.__=v.__N,v.__N=void 0,f!==v.__[0]&&(p=!0)}}),a){var i=a.call(this,u,_,c);return r?i||p:i}return!r||p};x.__f=!0;var a=x.shouldComponentUpdate,l=x.componentWillUpdate;x.componentWillUpdate=function(u,_,c){if(this.__e){var r=a;a=void 0,o(u,_,c),a=r}l&&l.call(this,u,_,c)},x.shouldComponentUpdate=o}return s.__N||s.__}function ee(t,e){var n=_e(U++,3);!C.__s&&Ke(n.__H,e)&&(n.__=t,n.u=e,x.__H.__h.push(n))}function ve(t){return F=5,te(function(){return{current:t}},[])}function te(t,e){var n=_e(U++,7);return Ke(n.__H,e)&&(n.__=t(),n.__H=e,n.__h=t),n.__}function he(t,e){return F=8,te(function(){return t},e)}function dt(){for(var t;t=We.shift();){var e=t.__H;if(t.__P&&e)try{e.__h.some(Z),e.__h.some(pe),e.__h=[]}catch(n){e.__h=[],C.__e(n,t.__v)}}}C.__b=function(t){x=null,je&&je(t)},C.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),Be&&Be(t,e)},C.__r=function(t){Le&&Le(t),U=0;var e=(x=t.__c).__H;e&&(ue===x?(e.__h=[],x.__h=[],e.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(e.__h.some(Z),e.__h.some(pe),e.__h=[],U=0)),ue=x},C.diffed=function(t){Ie&&Ie(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(We.push(e)!==1&&De===C.requestAnimationFrame||((De=C.requestAnimationFrame)||ut)(dt)),e.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),ue=x=null},C.__c=function(t,e){e.some(function(n){try{n.__h.some(Z),n.__h=n.__h.filter(function(s){return!s.__||pe(s)})}catch(s){e.some(function(o){o.__h&&(o.__h=[])}),e=[],C.__e(s,n.__v)}}),Ue&&Ue(t,e)},C.unmount=function(t){Fe&&Fe(t);var e,n=t.__c;n&&n.__H&&(n.__H.__.some(function(s){try{Z(s)}catch(o){e=o}}),n.__H=void 0,e&&C.__e(e,n.__v))};var Ve=typeof requestAnimationFrame=="function";function ut(t){var e,n=function(){clearTimeout(s),Ve&&cancelAnimationFrame(e),setTimeout(t)},s=setTimeout(n,35);Ve&&(e=requestAnimationFrame(n))}function Z(t){var e=x,n=t.__c;typeof n=="function"&&(t.__c=void 0,n()),x=e}function pe(t){var e=x;t.__c=t.__(),x=e}function Ke(t,e){return!t||t.length!==e.length||e.some(function(n,s){return n!==t[s]})}function ze(t,e){return typeof e=="function"?e(t):e}var Ye=function(t,e,n,s){var o;e[0]=0;for(var a=1;a<e.length;a++){var l=e[a++],u=e[a]?(e[0]|=l?1:2,n[e[a++]]):e[++a];l===3?s[0]=u:l===4?s[1]=Object.assign(s[1]||{},u):l===5?(s[1]=s[1]||{})[e[++a]]=u:l===6?s[1][e[++a]]+=u+"":l?(o=t.apply(u,Ye(t,u,n,["",null])),s.push(o),u[0]?e[0]|=2:(e[a-2]=0,e[a]=o)):s.push(u)}return s},Oe=new Map;function Ge(t){var e=Oe.get(this);return e||(e=new Map,Oe.set(this,e)),(e=Ye(this,e.get(t)||(e.set(t,e=(function(n){for(var s,o,a=1,l="",u="",_=[0],c=function(i){a===1&&(i||(l=l.replace(/^\\s*\\n\\s*|\\s*\\n\\s*$/g,"")))?_.push(0,i,l):a===3&&(i||l)?(_.push(3,i,l),a=2):a===2&&l==="..."&&i?_.push(4,i,0):a===2&&l&&!i?_.push(5,0,!0,l):a>=5&&((l||!i&&a===5)&&(_.push(a,0,l,o),a=6),i&&(_.push(a,i,0,o),a=6)),l=""},r=0;r<n.length;r++){r&&(a===1&&c(),c(r));for(var p=0;p<n[r].length;p++)s=n[r][p],a===1?s==="<"?(c(),_=[_],a=3):l+=s:a===4?l==="--"&&s===">"?(a=1,l=""):l=s+l[0]:u?s===u?u="":l+=s:s===\'"\'||s==="\'"?u=s:s===">"?(c(),a=1):a&&(s==="="?(a=5,o=l,l=""):s==="/"&&(a<5||n[r][p+1]===">")?(c(),a===3&&(_=_[0]),a=_,(_=_[0]).push(2,0,a),a=0):s===" "||s===" "||s===`\n`||s==="\\r"?(c(),a=2):l+=s),a===3&&l==="!--"&&(a=4,_=_[0])}return c(),_})(t)),e),arguments,[])).length>1?e:e[0]}var d=Ge.bind(re),Je=window.__QRING__&&window.__QRING__.token||"",fe=Je?"?token="+encodeURIComponent(Je):"",A=t=>\'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="url(#neon-grad)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\'+t+"</svg>",k={health:A(\'<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>\'),environment:A(\'<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>\'),decay:A(\'<path d="M5 22h14"/><path d="M5 2h14"/><path d="M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22"/><path d="M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2"/>\'),superposition:A(\'<polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/>\'),entangle:A(\'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>\'),tunnel:A(\'<path d="M9 10h.01"/><path d="M15 10h.01"/><path d="M12 2a8 8 0 0 0-8 8v12l3-3 2.5 2.5L12 19l2.5 2.5L17 19l3 3V10a8 8 0 0 0-8-8z"/>\'),anomaly:A(\'<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>\'),audit:A(\'<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/>\'),key:A(\'<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/>\'),hook:A(\'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>\'),approve:A(\'<path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>\'),manifest:A(\'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>\'),policy:A(\'<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/>\'),memory:A(\'<rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><line x1="9" y1="2" x2="9" y2="4"/><line x1="15" y1="2" x2="15" y2="4"/><line x1="9" y1="20" x2="9" y2="22"/><line x1="15" y1="20" x2="15" y2="22"/><line x1="20" y1="9" x2="22" y2="9"/><line x1="20" y1="14" x2="22" y2="14"/><line x1="2" y1="9" x2="4" y2="9"/><line x1="2" y1="14" x2="4" y2="14"/>\'),folder:\'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>\',search:\'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>\',lock:\'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>\'};function $e(t){if(!t)return"env-default";let e=t.toLowerCase();return e==="prod"||e==="production"?"env-prod":e==="staging"||e==="stage"?"env-staging":e==="dev"||e==="development"?"env-dev":e==="test"||e==="testing"?"env-test":"env-default"}function Xe(t,e){return e||t>=90?"var(--danger)":t>=75?"var(--warning)":"var(--accent)"}function Ze(t){let e=new Date(t);return String(e.getHours()).padStart(2,"0")+":"+String(e.getMinutes()).padStart(2,"0")+":"+String(e.getSeconds()).padStart(2,"0")}function et(t){if(!t)return"\\u2014";let e=Math.floor((Date.now()-new Date(t).getTime())/1e3);return isNaN(e)?"\\u2014":e<5?"just now":e<60?e+"s ago":e<3600?Math.floor(e/60)+"m ago":e<86400?Math.floor(e/3600)+"h ago":Math.floor(e/86400)+"d ago"}function ye(t){return t==null?"\\u2014":t<0?"expired":t<60?t+"s":t<3600?Math.floor(t/60)+"m":t<86400?Math.floor(t/3600)+"h":Math.floor(t/86400)+"d"}var L=({svg:t})=>d`<span style="display:contents" dangerouslySetInnerHTML=${{__html:t}} />`;function M({icon:t,title:e,aside:n,asideStyle:s}){return d`<div class="card-title">\n <${L} svg=${t} />${e}\n ${n!=null?d`<span class="title-aside" style=${s||""}>${n}</span>`:null}\n </div>`}function S({delay:t=0,wide:e=!1,style:n="",children:s}){let o="card"+(e?" grid-wide":""),a="animation-delay:"+t+"ms"+(n?";"+n:"");return d`<div class=${o} style=${a}>${s}</div>`}function E({children:t,cta:e}){return d`<div class="empty">${t}${e?d`<span class="empty-cta">${e}</span>`:null}</div>`}function Qe({snap:t,paused:e,connState:n,onPause:s,onRefresh:o,lastUpdate:a}){let l=e?"paused":n==="live"?"live":n==="reconnecting"?"reconnecting\\u2026":"connecting\\u2026",u="status-dot"+(e?" paused":n==="reconnecting"?" disconnected":"");return d`\n <header class="header">\n <div class="header-left">\n <h1>\n <span class="q-icon"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="url(#neon-grad)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg></span>\n <span class="brand">q-ring</span>\n <span class="sub">quantum status</span>\n </h1>\n <span class="meta-chip" title="q-ring version">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>\n ${" v"+(t?t.version:"")}\n </span>\n <span class="meta-chip" title="Project working directory">\n <${L} svg=${k.folder} /> ${t?t.projectPath:""}\n </span>\n </div>\n <div class="header-right">\n <span class="conn-label" title="Last update from the live stream"><span>${a}</span></span>\n <button class="btn" type="button" title="Pause / resume the live stream (P)" onClick=${s}>\n ${e?d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>`:d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>`}\n <span>${e?"Resume":"Pause"}</span>\n </button>\n <button class="btn" type="button" title="Force-refresh now (R)" onClick=${o}>\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3.5-7.1"/><polyline points="21 3 21 9 15 9"/></svg>\n Refresh\n </button>\n <a class="btn" href=${"/api/status"+fe} target="_blank" rel="noopener" title="Open the raw JSON snapshot in a new tab">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>\n JSON\n </a>\n <span class="conn-label"><span class=${u}></span><span>${l}</span></span>\n </div>\n </header>\n `}function pt({snap:t}){let e=t,n=e.auditMetrics||{total:0,byAction:{},topRead:[]},s=n.byAction.read||0,o=(n.byAction.write||0)+(n.byAction.delete||0)+(n.byAction.rotate||0),a=n.byAction.policy_deny||0,l=(e.hooks||[]).filter(r=>r.enabled).length,u=(e.approvals||[]).filter(r=>r.valid).length,_=(e.anomalies||[]).length,c=[{label:"Secrets",icon:k.key,value:e.health.total,sub:e.health.healthy+" healthy \\xB7 "+e.health.stale+" stale \\xB7 "+e.health.expired+" expired",cls:""},{label:"Environment",icon:k.environment,value:e.environment?e.environment.env:"none",sub:e.environment?"via "+e.environment.source:"no env detected",cls:e.environment?"":"dim"},{label:"Protected",icon:k.lock,value:e.protectedCount,sub:"require approval",cls:e.protectedCount>0?"warning":"dim"},{label:"Approvals",icon:k.approve,value:u,sub:"active grants",cls:u>0?"green":"dim"},{label:"Hooks",icon:k.hook,value:l,sub:"enabled / "+(e.hooks||[]).length+" total",cls:l>0?"":"dim"},{label:"Reads (24h)",icon:k.audit,value:s,sub:o+" writes \\xB7 "+a+" denied",cls:""},{label:"Anomalies",icon:k.anomaly,value:_,sub:_?"investigate now":"all clear",cls:_?"danger":"green"}];return d`<section class="kpi-strip">\n ${c.map(r=>d`<div class="kpi" key=${r.label}>\n <div class="kpi-label"><${L} svg=${r.icon} />${r.label}</div>\n <div class="kpi-value ${r.cls}">${r.value}</div>\n <div class="kpi-sub">${r.sub}</div>\n </div>`)}\n </section>`}function _t({snap:t,delay:e}){let n=t.health,s=n.total||1,o=42,a=2*Math.PI*o,l=[{v:n.healthy,c:"var(--accent)"},{v:n.stale,c:"var(--warning)"},{v:n.expired,c:"var(--danger)"},{v:n.noDecay,c:"var(--text-dim)"}],u=0,_=l.map((r,p)=>{let i=r.v/s*a,v=d`<circle key=${p} cx="50" cy="50" r=${o} fill="none" stroke=${r.c} stroke-width="12" stroke-dasharray=${i+" "+(a-i)} stroke-dashoffset=${-u} stroke-linecap="round" opacity="0.85" />`;return u+=i,v}),c=t.scopes||{global:0,project:0,team:0,org:0};return d`<${S} delay=${e}>\n <${M} icon=${k.health} title="Health Summary" aside=${n.healthy+"/"+n.total+" healthy"} />\n <div class="health-row">\n <div class="donut-wrap">\n <svg viewBox="0 0 100 100" width="100" height="100">${_}</svg>\n <div class="donut-label">${n.total}<small>secrets</small></div>\n </div>\n <div class="health-legend">\n <div class="legend-item"><span class="legend-dot" style="background:var(--accent)"></span>Healthy ${n.healthy}</div>\n <div class="legend-item"><span class="legend-dot" style="background:var(--warning)"></span>Stale ${n.stale}</div>\n <div class="legend-item"><span class="legend-dot" style="background:var(--danger)"></span>Expired ${n.expired}</div>\n <div class="legend-item"><span class="legend-dot" style="background:var(--text-dim)"></span>No decay ${n.noDecay}</div>\n </div>\n </div>\n <div class="scope-row">\n ${["global","project","team","org"].filter(r=>c[r]).map(r=>d`<span class="scope-pill" key=${r}><strong>${c[r]}</strong>${r}</span>`)}\n </div>\n <//>`}function vt({snap:t,delay:e}){let n=t.environment;return d`<${S} delay=${e}>\n <${M} icon=${k.environment} title="Environment" />\n ${n?d`<div class="env-status"><span class="env-big env-pill ${$e(n.env)}">${n.env}</span><span class="env-source">detected via ${n.source}</span></div>`:d`<${E} cta="$ qring env --project-path .">No environment detected.<//>`}\n <//>`}function ht({snap:t,delay:e}){let n=t.manifest;if(!n)return d`<${S} delay=${e}>\n <${M} icon=${k.manifest} title="Manifest" />\n <${E} cta=${d`$ qring wizard <name>`}>No <code>.q-ring.json</code> manifest in this project.<//>\n <//>`;let s=n.required-n.missing.length-n.expired.length-n.stale.length,o=n.required?Math.max(0,Math.round(s/n.required*100)):100,a=n.missing.length?"var(--danger)":n.expired.length||n.stale.length?"var(--warning)":"var(--green)",l=(_,c,r)=>d`<div class="label">${_} (${c.length})</div><div>${c.map(p=>d`<span class="key-pill ${r}" key=${p}>${p}</span>`)}</div>`,u=n.missing.length||n.expired.length||n.stale.length;return d`<${S} delay=${e}>\n <${M} icon=${k.manifest} title="Manifest" aside=${n.required+" required / "+n.declared+" declared"} />\n <div class="manifest-bars">\n <div class="manifest-row"><span style="min-width:54px">healthy</span><div class="manifest-bar"><div class="manifest-fill" style=${"width:"+o+"%;background:"+a}></div></div><span>${o}%</span></div>\n </div>\n <div class="manifest-list">\n ${n.missing.length?l("Missing required",n.missing,"miss"):null}\n ${n.expired.length?l("Expired",n.expired,"exp"):null}\n ${n.stale.length?l("Stale",n.stale,"exp"):null}\n ${u?null:d`<div class="label">All required keys present and healthy.</div>`}\n </div>\n <//>`}function ft({snap:t,delay:e}){let n=t.policy||{counts:{}},s=n.counts||{};if(!(n.hasMcpPolicy||n.hasExecPolicy||n.hasSecretPolicy))return d`<${S} delay=${e}>\n <${M} icon=${k.policy} title="Policy" />\n <${E} cta=${d`add <code>policy</code> to <code>.q-ring.json</code>`}>No governance policy declared.<//>\n <//>`;let a=({label:u,value:_})=>d`<div class="policy-row"><span class="policy-label">${u}</span><span class="policy-value ${_?"":"zero"}">${_||"\\u2014"}</span></div>`,l=[n.hasMcpPolicy?"mcp":"",n.hasExecPolicy?"exec":"",n.hasSecretPolicy?"secrets":""].filter(Boolean).join(" \\xB7 ")||"none";return d`<${S} delay=${e}>\n <${M} icon=${k.policy} title="Policy" aside=${l} />\n <div class="policy-rows">\n <${a} label="MCP allow tools" value=${s.allowTools} />\n <${a} label="MCP deny tools" value=${s.denyTools} />\n <${a} label="Denied keys" value=${s.deniedKeys} />\n <${a} label="Denied tags" value=${s.deniedTags} />\n <${a} label="Exec allow" value=${s.allowCommands} />\n <${a} label="Exec deny" value=${s.denyCommands} />\n <${a} label="Tag \u2192 approval" value=${s.requireApprovalForTags} />\n <${a} label="Tag \u2192 rotation" value=${s.requireRotationFormatForTags} />\n ${n.maxTtlSeconds?d`<${a} label="Max TTL" value=${ye(n.maxTtlSeconds)} />`:null}\n ${n.maxRuntimeSeconds?d`<${a} label="Max exec runtime" value=${ye(n.maxRuntimeSeconds)} />`:null}\n </div>\n <//>`}function yt({snap:t,delay:e}){let n=(t.secrets||[]).filter(s=>s.decay&&s.decay.timeRemaining).sort((s,o)=>(s.decay.secondsRemaining||0)-(o.decay.secondsRemaining||0));return d`<${S} delay=${e}>\n <${M} icon=${k.decay} title="Decay Timers" aside=${n.length+" tracked"} />\n ${n.length?d`<div class="decay-list">${n.slice(0,12).map(s=>{let o=Math.min(s.decay.lifetimePercent,100),a=Xe(o,s.decay.isExpired),l=s.decay.isExpired?"expired":s.decay.timeRemaining||"";return d`<div class="decay-item" key=${s.scope+":"+s.key}>\n <span class="decay-key" title=${s.key}>${s.key}</span>\n <div class="decay-bar"><div class="decay-fill" style=${"width:"+o+"%;background:"+a}></div></div>\n <span class="decay-time" style=${"color:"+a}>${l}</span>\n </div>`})}</div>`:d`<${E} cta="$ qring set KEY --ttl 86400">No secrets with decay configured.<//>`}\n <//>`}function $t({snap:t,delay:e}){let n=(t.secrets||[]).filter(s=>s.type==="superposition"&&s.environments&&s.environments.length);return d`<${S} delay=${e}>\n <${M} icon=${k.superposition} title="Superposition" aside=${n.length+" multi-env"} />\n ${n.length?d`<div class="super-list">${n.slice(0,14).map(s=>d`<div class="super-item" key=${s.scope+":"+s.key}>\n <span class="super-key">${s.key}</span>\n ${(s.environments||[]).map(o=>d`<span class="env-pill ${$e(o)}" key=${o}>${o}${o===s.defaultEnv?" \\u2713":""}</span>`)}\n </div>`)}</div>`:d`<${E} cta="$ qring set KEY --env prod">No secrets in superposition.<//>`}\n <//>`}function mt({snap:t,delay:e}){let n=t.entanglements||[],s=new Set,o=n.filter(h=>{let y=[h.source.service,h.source.key,h.target.service,h.target.key].sort().join("|");return s.has(y)?!1:(s.add(y),!0)}),a=[],l=new Map;for(let h of o)for(let y of[h.source.key,h.target.key])l.has(y)||(l.set(y,a.length),a.push(y));let u=o.length>0&&a.length<=14,_=320,c=210,r=_/2,p=c/2,i=Math.min(_,c)/2-34,v=a.map((h,y)=>{let m=2*Math.PI*y/a.length-Math.PI/2;return{x:r+i*Math.cos(m),y:p+i*Math.sin(m)}}),f=h=>h.length>14?h.slice(0,12)+"\\u2026":h;return d`<${S} delay=${e}>\n <${M} icon=${k.entangle} title="Entanglement" aside=${o.length+" pair"+(o.length===1?"":"s")+" \\xB7 "+a.length+" keys"} />\n ${o.length?u?d`<svg class="entangle-graph" viewBox="0 0 ${_} ${c}" role="img" aria-label="Entanglement graph: ${o.length} linked pairs">\n ${o.map((h,y)=>{let m=v[l.get(h.source.key)],$=v[l.get(h.target.key)];return d`<line key=${"e"+y} x1=${m.x} y1=${m.y} x2=${$.x} y2=${$.y} class="entangle-edge" />`})}\n ${a.map((h,y)=>{let m=v[y],$=m.x>=r;return d`<g key=${"n"+y}>\n <circle cx=${m.x} cy=${m.y} r="5" class="entangle-node" />\n <text x=${m.x+($?9:-9)} y=${m.y+3.5} text-anchor=${$?"start":"end"} class="entangle-label">${f(h)}<title>${h}</title></text>\n </g>`})}\n </svg>`:d`<div class="entangle-list">${o.slice(0,12).map((h,y)=>d`<div class="entangle-pair" key=${y}>\n <span>${h.source.key}</span><span class="entangle-arrow">\u2194</span><span>${h.target.key}</span>\n </div>`)}</div>`:d`<${E} cta="$ qring entangle KEY_A KEY_B">No entangled secrets.<//>`}\n <//>`}function gt({snap:t,delay:e}){let n=t.tunnels||[];return d`<${S} delay=${e}>\n <${M} icon=${k.tunnel} title="Quantum Tunnels" aside=${n.length+" live"} />\n ${n.length?d`<div class="tunnel-list">${n.map(s=>{let o=s.expiresAt?Math.max(0,Math.floor((s.expiresAt-Date.now())/1e3)):null;return d`<div class="tunnel-card" key=${s.id}>${s.id}<div class="tunnel-meta">\n <span>reads: ${s.accessCount}${s.maxReads?"/"+s.maxReads:""}</span>\n ${o!==null?d`<span>expires: ${o}s</span>`:d`<span>no expiry</span>`}\n </div></div>`})}</div>`:d`<${E} cta=${d`$ qring tunnel create <value>`}>No active tunnels.<//>`}\n <//>`}function kt({snap:t,delay:e}){let n=t.approvals||[];return d`<${S} delay=${e}>\n <${M} icon=${k.approve} title="Approvals" aside=${n.filter(s=>s.valid).length+" valid"} />\n ${n.length?d`<div class="approval-list">${n.slice(0,8).map(s=>{let o=s.tampered?"tampered":s.secondsRemaining<300?"expiring":"";return d`<div class="approval-card ${o}" key=${s.id}>\n <div class="approval-head"><span>${s.key}${s.tampered?" \\u26A0 TAMPERED":""}</span><span>${ye(s.secondsRemaining)} left</span></div>\n <div class="approval-reason">${s.reason||"(no reason)"}</div>\n <div class="approval-meta"><span>scope:${s.scope}</span><span>by:${s.grantedBy}</span></div>\n </div>`})}</div>`:d`<${E} cta=${\'$ qring approve KEY --for 1800 --reason "..."\'}>No active approvals.<//>`}\n <//>`}function bt({snap:t,delay:e}){let n=t.hooks||[];return d`<${S} delay=${e}>\n <${M} icon=${k.hook} title="Hooks" aside=${n.filter(s=>s.enabled).length+" enabled / "+n.length} />\n ${n.length?d`<div class="hooks-list">${n.slice(0,8).map(s=>d`<div class="hook-row ${s.enabled?"":"disabled"}" key=${s.id}>\n <span class="hook-type ${s.type}">${s.type}</span>\n <span class="hook-summary" title=${s.matchSummary}>${s.description||s.matchSummary}</span>\n <span class="hook-id">${s.id}</span>\n </div>`)}</div>`:d`<${E} cta=${\'$ qring hook add --tag payments --action rotate --exec "..."\'}>No hooks registered.<//>`}\n <//>`}function xt({snap:t,delay:e}){return d`<${S} delay=${e}>\n <${M} icon=${k.memory} title="Agent Memory" />\n <div class="empty" style="display:flex;align-items:baseline;gap:8px;font-style:normal">\n <span style="font-size:1.6rem;font-weight:700;color:var(--text-primary);font-family:var(--font-display)">${t.memoryKeys||0}</span>\n <span>memory key${t.memoryKeys===1?"":"s"} encrypted at <code>~/.config/q-ring/agent-memory.enc</code></span>\n </div>\n <//>`}function wt({snap:t,delay:e}){let n=t.anomalies||[];if(!n.length)return d`<${S} delay=${e} wide=${!0}>\n <${M} icon=${k.anomaly} title="Anomaly Alerts" aside="all clear" asideStyle="color:var(--green)" />\n <${E}>No anomalies detected \u2014 quantum field is stable.<//>\n <//>`;let s=o=>o==="tampered"?"$ qring audit:verify":o==="burst"?"$ qring audit --key \\u2026 --action read":o==="unusual-hour"?\'$ qring audit --action read --since "1am"\':"$ qring audit --limit 100";return d`<${S} delay=${e} wide=${!0}>\n <${M} icon=${k.anomaly} title="Anomaly Alerts" aside=${n.length+" active"} asideStyle="color:var(--danger)" />\n <div class="anomaly-list">${n.map((o,a)=>d`<div class="anomaly-card" key=${a}>\n <div class="anomaly-type">${o.type}</div>\n <div class="anomaly-desc">${o.description}</div>\n <div class="anomaly-hint">${s(o.type)}</div>\n </div>`)}</div>\n <//>`}function Ct(t,e){let n=e.trim().toLowerCase();return n?n==="expired"?t.filter(s=>s.decay&&s.decay.isExpired):n==="stale"?t.filter(s=>s.decay&&s.decay.isStale&&!s.decay.isExpired):n==="protected"?t.filter(s=>s.requiresApproval):t.filter(s=>[s.key,s.scope,s.type,s.provider||"",s.defaultEnv||"",(s.environments||[]).join(" "),(s.tags||[]).join(" ")].join(" ").toLowerCase().indexOf(n)!==-1):t.slice()}function Mt(t,e){let n=e.dir==="asc"?1:-1;return t.sort((s,o)=>{let a,l;switch(e.col){case"key":a=s.key,l=o.key;break;case"scope":a=s.scope,l=o.scope;break;case"env":a=s.defaultEnv||(s.environments||[])[0]||"",l=o.defaultEnv||(o.environments||[])[0]||"";break;case"type":a=s.type,l=o.type;break;case"decay":a=s.decay&&s.decay.secondsRemaining!=null?s.decay.secondsRemaining:1/0,l=o.decay&&o.decay.secondsRemaining!=null?o.decay.secondsRemaining:1/0;break;case"tags":a=(s.tags||[]).join(","),l=(o.tags||[]).join(",");break;default:a=s.lastAccessedAt?new Date(s.lastAccessedAt).getTime():0,l=o.lastAccessedAt?new Date(o.lastAccessedAt).getTime():0}return a<l?-1*n:a>l?1*n:0})}function St({snap:t,query:e,setQuery:n,sort:s,setSort:o,searchRef:a}){let l=t.secrets||[],u=te(()=>Mt(Ct(l,e),s),[l,e,s]),_=[{id:"key",label:"Key"},{id:"scope",label:"Scope"},{id:"env",label:"Env"},{id:"type",label:"Type"},{id:"decay",label:"Decay"},{id:"tags",label:"Tags"},{id:"lastAccessedAt",label:"Last read"}],c=r=>{s.col===r?o({col:r,dir:s.dir==="asc"?"desc":"asc"}):o({col:r,dir:r==="key"?"asc":"desc"})};return d`<section><${S} wide=${!0} style="margin-bottom:16px">\n <${M} icon=${k.key} title="Secrets" aside=${u.length+" of "+l.length} />\n <div class="secrets-toolbar">\n <label class="search"><${L} svg=${k.search} /><input ref=${a} id="secretsSearch" type="search" placeholder="Filter by key, scope, env, tag, provider\u2026" autocomplete="off" value=${e} onInput=${r=>n(r.target.value)} /></label>\n <button class="btn" type="button" onClick=${()=>n("expired")}>${t.health.expired||0} expired</button>\n <button class="btn" type="button" onClick=${()=>n("stale")}>${t.health.stale||0} stale</button>\n <button class="btn" type="button" onClick=${()=>n("protected")}>${t.protectedCount||0} protected</button>\n <button class="btn" type="button" onClick=${()=>n("")}>clear</button>\n </div>\n <div class="secrets-table-wrap">\n ${u.length?d`<table class="secrets-table">\n <thead><tr>${_.map(r=>d`<th key=${r.id} class=${s.col===r.id?"sorted":""} onClick=${()=>c(r.id)}>${r.label}<span class="sort-arrow">${s.dir==="asc"?"\\u25B2":"\\u25BC"}</span></th>`)}</tr></thead>\n <tbody>${u.map(r=>{let p=r.type==="superposition"?(r.environments||[]).map(f=>d`<span class="env-pill ${$e(f)}" style="margin-right:3px" key=${f}>${f}${f===r.defaultEnv?" \\u2713":""}</span>`):d`<span class="env-pill env-default">\u2014</span>`,i=r.decay&&r.decay.timeRemaining?(()=>{let f=Math.min(r.decay.lifetimePercent,100),h=Xe(f,r.decay.isExpired);return d`<span class="mini-decay"><span class="mini-decay-bar"><span class="mini-decay-fill" style=${"width:"+f+"%;background:"+h}></span></span><span class="mini-decay-time" style=${"color:"+h}>${r.decay.isExpired?"expired":r.decay.timeRemaining}</span></span>`})():d`<span class="mini-decay-time">\u2014</span>`,v=r.tags||[];return d`<tr key=${r.scope+":"+r.key}>\n <td class="col-key" title=${r.key}>${r.key}${r.requiresApproval?d`<span class="protected-icon" title="requires approval for MCP read"><${L} svg=${k.lock} /></span>`:null}</td>\n <td><span class="scope-tag ${r.scope}">${r.scope}</span></td>\n <td>${p}</td>\n <td><span class="type-tag ${r.type}">${r.type}</span></td>\n <td class="col-decay">${i}</td>\n <td class="col-tags">${v.slice(0,3).map(f=>d`<span class="tag-pill" key=${f}>${f}</span>`)}${v.length>3?"+"+(v.length-3):""}</td>\n <td>${et(r.lastAccessedAt)}</td>\n </tr>`})}</tbody>\n </table>`:d`<div class="empty" style="padding:18px;text-align:center">No secrets match the filter.</div>`}\n </div>\n <//></section>`}function At({snap:t,delay:e,filter:n,setFilter:s}){let o=t.audit||[],a=t.auditMetrics||{byAction:{},bySource:{}},l=o.filter(p=>{if(n.action&&p.action!==n.action||n.source&&p.source!==n.source)return!1;let i=n.text.trim().toLowerCase();return!(i&&[p.key||"",p.action,p.source,p.detail||"",p.scope||"",p.env||""].join(" ").toLowerCase().indexOf(i)===-1)}),u=["read","write","delete","rotate","generate","entangle","tunnel","teleport","approve","revoke","policy_deny","collapse","export"],_=["cli","mcp","agent","ci","hook","api"],c=(p,i)=>s({...n,[p]:n[p]===i?"":i}),r=t.auditChain;return d`<${S} delay=${e} wide=${!0}>\n <${M} icon=${k.audit} title="Audit Log (24h)" aside=${l.length+" of "+o.length+" shown \\xB7 window "+(a.windowSeconds||86400)/3600+"h"} />\n ${r&&r.totalEvents>0?d`<div class="chain-badge ${r.intact?"ok":"broken"}" title="Hash-chain integrity \u2014 same check as qring audit:verify">\n ${r.intact?d`\u26D3 chain intact \xB7 ${r.totalEvents} events verified`:d`\u26D3 chain BROKEN at event #${r.brokenAt} \xB7 ${r.validEvents}/${r.totalEvents} valid \u2014 run $ qring audit:verify`}\n </div>`:null}\n <div class="audit-actions-strip">\n ${u.filter(p=>a.byAction[p]).length?u.filter(p=>a.byAction[p]).map(p=>d`<span class="audit-chip ${n.action===p?"active":""}" key=${p} onClick=${()=>c("action",p)}>${p}<strong>${a.byAction[p]}</strong></span>`):d`<span class="empty" style="padding:0">no actions</span>`}\n </div>\n ${_.filter(p=>a.bySource[p]).length?d`<div class="audit-actions-strip">${_.filter(p=>a.bySource[p]).map(p=>d`<span class="audit-chip ${n.source===p?"active":""}" key=${p} onClick=${()=>c("source",p)}>${p}<strong>${a.bySource[p]}</strong></span>`)}</div>`:null}\n <div class="audit-toolbar">\n <label class="search"><${L} svg=${k.search} /><input id="auditSearch" type="search" placeholder="Filter by key, detail, scope\u2026" autocomplete="off" value=${n.text} onInput=${p=>s({...n,text:p.target.value})} /></label>\n <button class="btn" type="button" onClick=${()=>s({action:"",source:"",text:""})}>clear</button>\n </div>\n ${l.length?d`<div class="audit-feed">${l.slice(0,80).map((p,i)=>d`<div class="audit-row" key=${i}>\n <span class="audit-ts" title=${p.timestamp}>${Ze(p.timestamp)}</span>\n <span class="audit-action ${p.action}">${p.action}</span>\n <span class="audit-source">${p.source}</span>\n <span><span class="audit-key">${p.key||"\\u2014"}</span> <span class="audit-detail">${p.detail||""}</span></span>\n </div>`)}</div>`:d`<${E}>No audit events match the filter.<//>`}\n <//>`}function Et(){let[t,e]=N(null),[n,s]=N(!1),[o,a]=N("connecting"),[l,u]=N(""),[_,c]=N({col:"lastAccessedAt",dir:"desc"}),[r,p]=N({action:"",source:"",text:""}),[,i]=N(0),v=ve(n);v.current=n;let f=ve(null),h=he(g=>{try{e(typeof g=="string"?JSON.parse(g):g)}catch{}},[]),y=he(()=>{fetch("/api/status"+fe,{cache:"no-store"}).then(g=>g.json()).then(h).catch(()=>{})},[h]);ee(()=>{let g=new EventSource("/events"+fe);return g.onopen=()=>a("live"),g.onmessage=w=>{v.current||h(w.data)},g.onerror=()=>a("reconnecting"),()=>g.close()},[h]),ee(()=>{let g=setInterval(()=>i(w=>w+1),5e3);return()=>clearInterval(g)},[]),ee(()=>{let g=w=>{let P=w.target&&w.target.tagName;if(P==="INPUT"||P==="TEXTAREA"){w.key==="Escape"&&w.target.blur();return}w.key==="/"?(w.preventDefault(),f.current&&f.current.focus()):w.key==="p"||w.key==="P"?s(H=>!H):(w.key==="r"||w.key==="R")&&y()};return document.addEventListener("keydown",g),()=>document.removeEventListener("keydown",g)},[y]);let m=t?"updated "+et(t.timestamp):"\\u2014";if(!t)return d`<div class="container">\n <${Qe} snap=${null} paused=${n} connState=${o} onPause=${()=>s(g=>!g)} onRefresh=${y} lastUpdate=${m} />\n <p class="foot"><span>Connecting to the live quantum stream\u2026</span></p>\n </div>`;let $=t.auditMetrics||{total:0};return d`<div class="container">\n <${Qe} snap=${t} paused=${n} connState=${o} onPause=${()=>s(g=>!g)} onRefresh=${y} lastUpdate=${m} />\n <${pt} snap=${t} />\n <section class="grid">\n <${_t} snap=${t} delay=${0} />\n <${vt} snap=${t} delay=${60} />\n <${ht} snap=${t} delay=${120} />\n <${ft} snap=${t} delay=${180} />\n </section>\n <${St} snap=${t} query=${l} setQuery=${u} sort=${_} setSort=${c} searchRef=${f} />\n <section class="grid">\n <${yt} snap=${t} delay=${0} />\n <${$t} snap=${t} delay=${60} />\n <${mt} snap=${t} delay=${120} />\n <${gt} snap=${t} delay=${180} />\n </section>\n <section class="grid">\n <${kt} snap=${t} delay=${0} />\n <${bt} snap=${t} delay=${60} />\n <${xt} snap=${t} delay=${120} />\n </section>\n <section class="grid">\n <${wt} snap=${t} delay=${0} />\n <${At} snap=${t} delay=${60} filter=${r} setFilter=${p} />\n </section>\n <p class="foot">\n <span>${"q-ring v"+t.version+" \\xB7 snapshot "+Ze(t.timestamp)+" \\xB7 "+($.total||0)+" audit events in last 24h"}</span>\n \xB7 keyboard: <span class="kbd">/</span> search \xB7 <span class="kbd">P</span> pause \xB7 <span class="kbd">R</span> refresh\n </p>\n </div>`}He(d`<${Et} />`,document.getElementById("app"));})();';
|
|
25
|
-
|
|
26
|
-
// src/core/dashboard-html.ts
|
|
27
|
-
function jsString(value) {
|
|
28
|
-
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
29
|
-
}
|
|
30
|
-
function getDashboardHtml(token) {
|
|
31
|
-
return `<!DOCTYPE html>
|
|
32
|
-
<html lang="en">
|
|
33
|
-
<head>
|
|
34
|
-
<meta charset="utf-8"/>
|
|
35
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
36
|
-
<title>q-ring \u2014 quantum status</title>
|
|
37
|
-
<style>
|
|
38
|
-
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
39
|
-
:root{
|
|
40
|
-
--bg-deep:#04080f;
|
|
41
|
-
--bg-section:#080e18;
|
|
42
|
-
--bg-card:#0f1a2e;
|
|
43
|
-
--bg-card-hover:#142240;
|
|
44
|
-
--border:#1a2d4a;
|
|
45
|
-
--border-glow:#0ea5e9;
|
|
46
|
-
|
|
47
|
-
--text-primary:#f8f8ff;
|
|
48
|
-
--text-secondary:#c8cfe0;
|
|
49
|
-
--text-dim:#8899b4;
|
|
50
|
-
|
|
51
|
-
--accent:#0ea5e9;
|
|
52
|
-
--accent-bright:#38bdf8;
|
|
53
|
-
--accent-dim:rgba(14,165,233,0.15);
|
|
54
|
-
--accent-glow:rgba(14,165,233,0.4);
|
|
55
|
-
|
|
56
|
-
--danger:#ff5e5b;
|
|
57
|
-
--warning:#fbbf24;
|
|
58
|
-
--green:#22c55e;
|
|
59
|
-
--violet:#a855f7;
|
|
60
|
-
--pink:#ff0055;
|
|
61
|
-
|
|
62
|
-
--font-display:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
|
|
63
|
-
--font-mono:'SF Mono','Cascadia Code','Fira Code',Consolas,'Liberation Mono',monospace;
|
|
64
|
-
|
|
65
|
-
--radius:12px;
|
|
66
|
-
--radius-sm:8px;
|
|
67
|
-
--radius-lg:20px;
|
|
68
|
-
|
|
69
|
-
--glass-bg:rgba(15,26,46,0.65);
|
|
70
|
-
--glass-border:rgba(26,45,74,0.8);
|
|
71
|
-
--shadow-card:0 4px 24px -1px rgba(0,0,0,0.4),0 0 1px rgba(255,255,255,0.04);
|
|
72
|
-
--shadow-glow:0 0 20px rgba(14,165,233,0.12),0 0 40px rgba(168,85,247,0.08);
|
|
73
|
-
}
|
|
74
|
-
html{background:var(--bg-deep);color:var(--text-primary);font-family:var(--font-display);font-size:16px;line-height:1.5}
|
|
75
|
-
body{min-height:100vh;overflow-x:hidden;position:relative}
|
|
76
|
-
|
|
77
|
-
/* Hidden SVG defs for gradient icons */
|
|
78
|
-
.svg-defs{position:absolute;width:0;height:0;overflow:hidden}
|
|
79
|
-
|
|
80
|
-
/* Mesh blobs */
|
|
81
|
-
.blob{position:fixed;border-radius:50%;filter:blur(100px);opacity:.12;pointer-events:none;z-index:0}
|
|
82
|
-
.blob-1{width:600px;height:600px;top:-120px;left:-100px;background:radial-gradient(circle,var(--accent),transparent 70%);animation:drift1 22s ease-in-out infinite}
|
|
83
|
-
.blob-2{width:500px;height:500px;bottom:-80px;right:-60px;background:radial-gradient(circle,var(--violet),transparent 70%);animation:drift2 26s ease-in-out infinite}
|
|
84
|
-
.blob-3{width:350px;height:350px;top:40%;left:50%;background:radial-gradient(circle,var(--green),transparent 70%);animation:drift3 30s ease-in-out infinite;opacity:.06}
|
|
85
|
-
@keyframes drift1{0%,100%{transform:translate(0,0) scale(1)}33%{transform:translate(60px,-40px) scale(1.08)}66%{transform:translate(-30px,50px) scale(.95)}}
|
|
86
|
-
@keyframes drift2{0%,100%{transform:translate(0,0) scale(1)}33%{transform:translate(-50px,30px) scale(1.05)}66%{transform:translate(40px,-60px) scale(.92)}}
|
|
87
|
-
@keyframes drift3{0%,100%{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-40%,-60%) scale(1.1)}}
|
|
88
|
-
|
|
89
|
-
.container{position:relative;z-index:1;max-width:1320px;margin:0 auto;padding:20px 20px 48px}
|
|
90
|
-
|
|
91
|
-
/* Header */
|
|
92
|
-
.header{position:sticky;top:0;z-index:5;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:14px;margin-bottom:20px;padding:14px 18px;background:rgba(4,8,15,0.85);backdrop-filter:blur(16px) saturate(1.2);-webkit-backdrop-filter:blur(16px) saturate(1.2);border:1px solid var(--border);border-radius:var(--radius)}
|
|
93
|
-
.header-left{display:flex;align-items:center;gap:14px;flex-wrap:wrap;min-width:0}
|
|
94
|
-
.header h1{font-family:var(--font-display);font-size:1.45rem;font-weight:700;letter-spacing:-.02em;display:flex;align-items:center;gap:10px}
|
|
95
|
-
.header h1 .q-icon{display:flex;filter:drop-shadow(0 0 6px rgba(14,165,233,0.6))}
|
|
96
|
-
.header h1 .brand{background:linear-gradient(135deg,#00D1FF,var(--violet));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
|
|
97
|
-
.header h1 .sub{color:var(--text-dim);font-weight:400;font-size:1rem;-webkit-text-fill-color:var(--text-dim)}
|
|
98
|
-
.meta-chip{font-family:var(--font-mono);font-size:.72rem;color:var(--text-dim);background:rgba(255,255,255,.04);border:1px solid var(--border);padding:3px 8px;border-radius:99px;display:inline-flex;align-items:center;gap:6px;max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
99
|
-
.meta-chip svg{width:11px;height:11px;flex-shrink:0;opacity:.7}
|
|
100
|
-
.header-right{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
|
|
101
|
-
.status-dot{width:8px;height:8px;border-radius:50%;background:var(--green);box-shadow:0 0 8px var(--green);display:inline-block;animation:pulse 2s ease-in-out infinite}
|
|
102
|
-
.status-dot.disconnected{background:var(--danger);box-shadow:0 0 8px var(--danger);animation:none}
|
|
103
|
-
.status-dot.paused{background:var(--warning);box-shadow:0 0 8px var(--warning);animation:none}
|
|
104
|
-
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
|
105
|
-
.conn-label{font-size:.78rem;color:var(--text-dim);display:flex;align-items:center;gap:6px;font-family:var(--font-mono)}
|
|
106
|
-
.btn{font-family:var(--font-display);font-size:.78rem;font-weight:500;color:var(--text-secondary);background:rgba(255,255,255,.04);border:1px solid var(--border);padding:5px 11px;border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;gap:5px;transition:background .2s,border-color .2s,color .2s}
|
|
107
|
-
.btn:hover{background:rgba(14,165,233,.08);border-color:var(--accent);color:var(--text-primary)}
|
|
108
|
-
.btn svg{width:13px;height:13px}
|
|
109
|
-
.btn.active{background:var(--accent-dim);color:var(--accent-bright);border-color:rgba(14,165,233,.4)}
|
|
110
|
-
.kbd{font-family:var(--font-mono);font-size:.65rem;color:var(--text-dim);background:rgba(255,255,255,.06);border:1px solid var(--border);border-bottom-width:2px;padding:1px 5px;border-radius:4px;margin-left:4px}
|
|
111
|
-
|
|
112
|
-
/* KPI strip */
|
|
113
|
-
.kpi-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:20px}
|
|
114
|
-
.kpi{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--glass-border);border-radius:var(--radius);padding:12px 14px;display:flex;flex-direction:column;gap:2px;transition:border-color .25s,transform .25s}
|
|
115
|
-
.kpi:hover{border-color:var(--border-glow);transform:translateY(-2px)}
|
|
116
|
-
.kpi-label{font-size:.66rem;text-transform:uppercase;letter-spacing:.1em;color:var(--text-dim);font-weight:600;display:flex;align-items:center;gap:6px}
|
|
117
|
-
.kpi-label svg{width:12px;height:12px;flex-shrink:0}
|
|
118
|
-
.kpi-value{font-family:var(--font-display);font-size:1.5rem;font-weight:700;line-height:1.1;color:var(--text-primary)}
|
|
119
|
-
.kpi-value.warning{color:var(--warning)}
|
|
120
|
-
.kpi-value.danger{color:var(--danger)}
|
|
121
|
-
.kpi-value.green{color:var(--green)}
|
|
122
|
-
.kpi-value.dim{color:var(--text-dim)}
|
|
123
|
-
.kpi-sub{font-size:.7rem;color:var(--text-dim);font-family:var(--font-mono)}
|
|
124
|
-
|
|
125
|
-
/* Grid */
|
|
126
|
-
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:16px;margin-bottom:16px}
|
|
127
|
-
.grid-wide{grid-column:1/-1}
|
|
128
|
-
|
|
129
|
-
/* Cards \u2014 reveal animation */
|
|
130
|
-
.card{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--glass-border);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow-card);transition:border-color .3s,box-shadow .3s,transform .3s;opacity:0;transform:translateY(16px);animation:cardReveal .5s cubic-bezier(0.16,1,0.3,1) forwards}
|
|
131
|
-
.card:hover{border-color:var(--border-glow);box-shadow:var(--shadow-card),var(--shadow-glow)}
|
|
132
|
-
@keyframes cardReveal{to{opacity:1;transform:translateY(0)}}
|
|
133
|
-
|
|
134
|
-
.card-title{font-family:var(--font-display);font-size:.78rem;text-transform:uppercase;letter-spacing:.1em;color:var(--text-dim);margin-bottom:14px;display:flex;align-items:center;gap:8px;font-weight:600}
|
|
135
|
-
.card-title svg{width:16px;height:16px;flex-shrink:0;filter:drop-shadow(0 0 4px rgba(14,165,233,0.4))}
|
|
136
|
-
.card-title .title-aside{margin-left:auto;font-size:.7rem;color:var(--text-dim);font-weight:400;letter-spacing:.04em;text-transform:none;display:flex;align-items:center;gap:6px}
|
|
137
|
-
|
|
138
|
-
/* Health donut */
|
|
139
|
-
.health-row{display:flex;align-items:center;gap:24px}
|
|
140
|
-
.donut-wrap{position:relative;width:100px;height:100px;flex-shrink:0}
|
|
141
|
-
.donut-wrap svg{transform:rotate(-90deg)}
|
|
142
|
-
.donut-wrap .donut-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;font-size:1.5rem;font-weight:700;line-height:1;font-family:var(--font-display)}
|
|
143
|
-
.donut-wrap .donut-label small{font-size:.7rem;color:var(--text-dim);font-weight:400;margin-top:2px;letter-spacing:.04em}
|
|
144
|
-
.health-legend{display:flex;flex-direction:column;gap:6px;font-family:var(--font-mono)}
|
|
145
|
-
.legend-item{display:flex;align-items:center;gap:8px;font-size:.82rem}
|
|
146
|
-
.legend-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
147
|
-
.scope-row{display:flex;gap:6px;margin-top:14px;flex-wrap:wrap;font-family:var(--font-mono);font-size:.72rem;color:var(--text-dim)}
|
|
148
|
-
.scope-pill{padding:2px 8px;border-radius:99px;background:rgba(255,255,255,.04);border:1px solid var(--border)}
|
|
149
|
-
.scope-pill strong{color:var(--text-primary);margin-right:4px;font-weight:600}
|
|
150
|
-
|
|
151
|
-
/* Decay bars */
|
|
152
|
-
.decay-list{display:flex;flex-direction:column;gap:8px;max-height:280px;overflow-y:auto}
|
|
153
|
-
.decay-item{display:flex;align-items:center;gap:10px}
|
|
154
|
-
.decay-key{font-family:var(--font-mono);font-size:.85rem;min-width:120px;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
155
|
-
.decay-bar{flex:1;height:6px;border-radius:3px;background:rgba(255,255,255,0.06);overflow:hidden;position:relative}
|
|
156
|
-
.decay-fill{height:100%;border-radius:3px;transition:width .6s ease}
|
|
157
|
-
.decay-time{font-size:.8rem;color:var(--text-dim);min-width:60px;text-align:right;font-family:var(--font-mono)}
|
|
158
|
-
|
|
159
|
-
/* Superposition pills */
|
|
160
|
-
.super-list{display:flex;flex-direction:column;gap:8px;max-height:280px;overflow-y:auto}
|
|
161
|
-
.super-item{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
162
|
-
.super-key{font-family:var(--font-mono);font-size:.85rem;min-width:100px}
|
|
163
|
-
.env-pill{font-size:.72rem;padding:2px 8px;border-radius:99px;font-weight:600;letter-spacing:.03em;font-family:var(--font-mono)}
|
|
164
|
-
.env-prod{background:rgba(255,0,85,0.2);color:var(--pink);border:1px solid rgba(255,0,85,0.3)}
|
|
165
|
-
.env-staging{background:rgba(251,191,36,0.15);color:var(--warning);border:1px solid rgba(251,191,36,0.25)}
|
|
166
|
-
.env-dev{background:rgba(34,197,94,0.15);color:var(--green);border:1px solid rgba(34,197,94,0.25)}
|
|
167
|
-
.env-default{background:rgba(168,85,247,0.15);color:var(--violet);border:1px solid rgba(168,85,247,0.25)}
|
|
168
|
-
.env-test{background:rgba(14,165,233,0.15);color:var(--accent-bright);border:1px solid rgba(14,165,233,0.25)}
|
|
169
|
-
|
|
170
|
-
/* Entanglement */
|
|
171
|
-
.entangle-list{display:flex;flex-direction:column;gap:6px;max-height:240px;overflow-y:auto}
|
|
172
|
-
.entangle-pair{display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.83rem}
|
|
173
|
-
.entangle-arrow{color:var(--accent-bright)}
|
|
174
|
-
.entangle-graph{display:block;width:100%;height:auto;max-height:260px}
|
|
175
|
-
.entangle-edge{stroke:var(--accent);stroke-opacity:.45;stroke-width:1.2}
|
|
176
|
-
.entangle-node{fill:var(--accent-bright);stroke:var(--accent-glow);stroke-width:3;paint-order:stroke}
|
|
177
|
-
.entangle-label{fill:var(--text-secondary);font-family:var(--font-mono);font-size:9px}
|
|
178
|
-
|
|
179
|
-
/* Audit chain badge */
|
|
180
|
-
.chain-badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-mono);font-size:.78rem;padding:4px 10px;border-radius:999px;margin-bottom:10px}
|
|
181
|
-
.chain-badge.ok{color:var(--green);background:rgba(34,197,94,.1);border:1px solid rgba(34,197,94,.25)}
|
|
182
|
-
.chain-badge.broken{color:var(--danger);background:rgba(255,94,91,.12);border:1px solid rgba(255,94,91,.3)}
|
|
183
|
-
|
|
184
|
-
/* Tunnels */
|
|
185
|
-
.tunnel-list{display:flex;flex-direction:column;gap:8px;max-height:240px;overflow-y:auto}
|
|
186
|
-
.tunnel-card{background:rgba(168,85,247,0.06);border:1px solid rgba(168,85,247,0.15);border-radius:var(--radius-sm);padding:10px 12px;font-size:.83rem;font-family:var(--font-mono)}
|
|
187
|
-
.tunnel-meta{display:flex;gap:12px;margin-top:4px;font-size:.78rem;color:var(--text-dim)}
|
|
188
|
-
|
|
189
|
-
/* Audit feed */
|
|
190
|
-
.audit-toolbar{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px;align-items:center}
|
|
191
|
-
.audit-actions-strip{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}
|
|
192
|
-
.audit-chip{font-family:var(--font-mono);font-size:.7rem;padding:2px 9px;border-radius:99px;background:rgba(255,255,255,.04);border:1px solid var(--border);color:var(--text-secondary);cursor:pointer;transition:all .2s}
|
|
193
|
-
.audit-chip:hover{border-color:var(--accent);color:var(--text-primary)}
|
|
194
|
-
.audit-chip.active{background:var(--accent-dim);color:var(--accent-bright);border-color:rgba(14,165,233,.4)}
|
|
195
|
-
.audit-chip strong{color:var(--text-primary);margin-left:5px;font-weight:600}
|
|
196
|
-
.audit-feed{display:flex;flex-direction:column;gap:2px;max-height:340px;overflow-y:auto;font-size:.82rem;font-family:var(--font-mono)}
|
|
197
|
-
.audit-row{display:grid;grid-template-columns:78px 76px 56px 1fr;gap:8px;padding:4px 0;border-bottom:1px solid rgba(255,255,255,0.03);align-items:baseline}
|
|
198
|
-
.audit-ts{color:var(--text-dim)}
|
|
199
|
-
.audit-action{font-weight:600}
|
|
200
|
-
.audit-action.read{color:var(--accent)}.audit-action.write{color:var(--green)}.audit-action.delete{color:var(--danger)}
|
|
201
|
-
.audit-action.entangle{color:var(--violet)}.audit-action.tunnel{color:var(--violet)}.audit-action.teleport{color:var(--warning)}
|
|
202
|
-
.audit-action.generate{color:var(--warning)}.audit-action.list{color:var(--text-dim)}.audit-action.export{color:var(--text-dim)}
|
|
203
|
-
.audit-action.collapse{color:var(--accent)}.audit-action.approve{color:var(--green)}.audit-action.revoke{color:var(--danger)}
|
|
204
|
-
.audit-action.policy_deny{color:var(--danger)}.audit-action.rotate{color:var(--violet)}
|
|
205
|
-
.audit-source{color:var(--text-dim);font-size:.72rem;text-transform:uppercase;letter-spacing:.04em}
|
|
206
|
-
.audit-detail{color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
207
|
-
.audit-key{color:var(--text-secondary)}
|
|
208
|
-
|
|
209
|
-
/* Anomalies */
|
|
210
|
-
.anomaly-list{display:flex;flex-direction:column;gap:8px}
|
|
211
|
-
.anomaly-card{background:rgba(255,94,91,0.06);border:1px solid rgba(255,94,91,0.15);border-radius:var(--radius-sm);padding:10px 14px;animation:anomaly-pulse 3s ease-in-out infinite}
|
|
212
|
-
@keyframes anomaly-pulse{0%,100%{border-color:rgba(255,94,91,0.15)}50%{border-color:rgba(255,94,91,0.4)}}
|
|
213
|
-
.anomaly-type{font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;color:var(--danger);font-weight:700;margin-bottom:2px;font-family:var(--font-display)}
|
|
214
|
-
.anomaly-desc{font-size:.86rem;color:var(--text-primary)}
|
|
215
|
-
.anomaly-hint{font-size:.74rem;color:var(--text-dim);margin-top:4px;font-family:var(--font-mono)}
|
|
216
|
-
|
|
217
|
-
/* Environment badge */
|
|
218
|
-
.env-status{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
|
219
|
-
.env-big{font-size:1rem;font-weight:700;padding:4px 14px;border-radius:var(--radius-sm)}
|
|
220
|
-
.env-source{font-size:.78rem;color:var(--text-dim);font-family:var(--font-mono)}
|
|
221
|
-
|
|
222
|
-
/* Manifest */
|
|
223
|
-
.manifest-bars{display:flex;flex-direction:column;gap:8px}
|
|
224
|
-
.manifest-row{display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.78rem}
|
|
225
|
-
.manifest-bar{flex:1;height:6px;border-radius:3px;background:rgba(255,255,255,.06);overflow:hidden}
|
|
226
|
-
.manifest-fill{height:100%;border-radius:3px}
|
|
227
|
-
.manifest-list{margin-top:10px;display:flex;flex-direction:column;gap:3px;font-family:var(--font-mono);font-size:.78rem;color:var(--text-secondary)}
|
|
228
|
-
.manifest-list .label{color:var(--text-dim);text-transform:uppercase;font-size:.66rem;letter-spacing:.08em;margin-top:6px}
|
|
229
|
-
.manifest-list .key-pill{display:inline-block;padding:1px 6px;background:rgba(255,255,255,.04);border:1px solid var(--border);border-radius:4px;margin:1px 3px 1px 0;font-size:.74rem}
|
|
230
|
-
.manifest-list .key-pill.miss{color:var(--danger);border-color:rgba(255,94,91,.3)}
|
|
231
|
-
.manifest-list .key-pill.exp{color:var(--warning);border-color:rgba(251,191,36,.3)}
|
|
232
|
-
|
|
233
|
-
/* Policy */
|
|
234
|
-
.policy-rows{display:flex;flex-direction:column;gap:6px;font-family:var(--font-mono);font-size:.78rem;color:var(--text-secondary)}
|
|
235
|
-
.policy-row{display:flex;justify-content:space-between;padding:2px 0;border-bottom:1px solid rgba(255,255,255,.04)}
|
|
236
|
-
.policy-label{color:var(--text-dim)}
|
|
237
|
-
.policy-value{color:var(--text-primary)}
|
|
238
|
-
.policy-value.zero{color:var(--text-dim)}
|
|
239
|
-
|
|
240
|
-
/* Approvals */
|
|
241
|
-
.approval-list{display:flex;flex-direction:column;gap:8px;max-height:240px;overflow-y:auto}
|
|
242
|
-
.approval-card{background:rgba(34,197,94,.05);border:1px solid rgba(34,197,94,.2);border-radius:var(--radius-sm);padding:10px 12px;font-size:.82rem}
|
|
243
|
-
.approval-card.tampered{background:rgba(255,94,91,.06);border-color:rgba(255,94,91,.4)}
|
|
244
|
-
.approval-card.expiring{background:rgba(251,191,36,.06);border-color:rgba(251,191,36,.3)}
|
|
245
|
-
.approval-head{display:flex;justify-content:space-between;gap:8px;font-family:var(--font-mono);font-weight:600}
|
|
246
|
-
.approval-reason{color:var(--text-dim);font-size:.76rem;margin-top:3px}
|
|
247
|
-
.approval-meta{display:flex;gap:12px;margin-top:4px;font-size:.72rem;color:var(--text-dim);font-family:var(--font-mono)}
|
|
248
|
-
|
|
249
|
-
/* Hooks */
|
|
250
|
-
.hooks-list{display:flex;flex-direction:column;gap:6px;max-height:240px;overflow-y:auto}
|
|
251
|
-
.hook-row{display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.8rem;padding:6px 10px;background:rgba(255,255,255,.03);border:1px solid var(--border);border-radius:var(--radius-sm)}
|
|
252
|
-
.hook-row.disabled{opacity:.5}
|
|
253
|
-
.hook-type{font-size:.7rem;text-transform:uppercase;font-weight:600;padding:1px 6px;border-radius:99px;letter-spacing:.04em}
|
|
254
|
-
.hook-type.shell{background:rgba(168,85,247,.15);color:var(--violet)}
|
|
255
|
-
.hook-type.http{background:rgba(14,165,233,.15);color:var(--accent-bright)}
|
|
256
|
-
.hook-type.signal{background:rgba(251,191,36,.15);color:var(--warning)}
|
|
257
|
-
.hook-summary{flex:1;color:var(--text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
258
|
-
.hook-id{color:var(--text-dim);font-size:.72rem}
|
|
259
|
-
|
|
260
|
-
/* Secrets table */
|
|
261
|
-
.secrets-toolbar{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;align-items:center}
|
|
262
|
-
.search{flex:1;min-width:180px;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.04);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px 10px;transition:border-color .2s}
|
|
263
|
-
.search:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px rgba(14,165,233,.12)}
|
|
264
|
-
.search svg{width:13px;height:13px;color:var(--text-dim);flex-shrink:0}
|
|
265
|
-
.search input{flex:1;background:transparent;border:none;outline:none;color:var(--text-primary);font-family:var(--font-mono);font-size:.82rem}
|
|
266
|
-
.search input::placeholder{color:var(--text-dim)}
|
|
267
|
-
.secrets-table-wrap{max-height:380px;overflow:auto;border:1px solid var(--border);border-radius:var(--radius-sm);background:rgba(4,8,15,.4)}
|
|
268
|
-
.secrets-table{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:.78rem}
|
|
269
|
-
.secrets-table thead th{position:sticky;top:0;background:rgba(8,14,24,.95);backdrop-filter:blur(8px);text-align:left;padding:8px 10px;color:var(--text-dim);font-weight:600;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--border);cursor:pointer;user-select:none;white-space:nowrap}
|
|
270
|
-
.secrets-table thead th:hover{color:var(--text-primary)}
|
|
271
|
-
.secrets-table thead th .sort-arrow{display:inline-block;margin-left:4px;color:var(--accent-bright);opacity:0;font-size:.7rem}
|
|
272
|
-
.secrets-table thead th.sorted .sort-arrow{opacity:1}
|
|
273
|
-
.secrets-table tbody td{padding:6px 10px;border-bottom:1px solid rgba(255,255,255,.03);color:var(--text-secondary);vertical-align:middle}
|
|
274
|
-
.secrets-table tbody tr:hover td{background:rgba(14,165,233,.05);color:var(--text-primary)}
|
|
275
|
-
.secrets-table .col-key{color:var(--text-primary);font-weight:500;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
276
|
-
.secrets-table .col-decay{min-width:90px}
|
|
277
|
-
.secrets-table .col-tags{max-width:200px;overflow:hidden}
|
|
278
|
-
.tag-pill{display:inline-block;font-size:.68rem;padding:1px 6px;background:rgba(168,85,247,.1);color:var(--violet);border:1px solid rgba(168,85,247,.2);border-radius:99px;margin-right:3px;font-family:var(--font-mono)}
|
|
279
|
-
.scope-tag{display:inline-block;font-size:.68rem;padding:1px 6px;border-radius:4px;letter-spacing:.04em;font-weight:600;text-transform:uppercase}
|
|
280
|
-
.scope-tag.global{background:rgba(14,165,233,.15);color:var(--accent-bright)}
|
|
281
|
-
.scope-tag.project{background:rgba(34,197,94,.15);color:var(--green)}
|
|
282
|
-
.scope-tag.team{background:rgba(168,85,247,.15);color:var(--violet)}
|
|
283
|
-
.scope-tag.org{background:rgba(251,191,36,.15);color:var(--warning)}
|
|
284
|
-
.type-tag{display:inline-block;font-size:.68rem;padding:1px 6px;border-radius:4px;letter-spacing:.04em;text-transform:uppercase;background:rgba(255,255,255,.05);color:var(--text-dim)}
|
|
285
|
-
.type-tag.superposition{background:rgba(168,85,247,.12);color:var(--violet)}
|
|
286
|
-
.protected-icon{color:var(--warning);margin-left:4px;display:inline-flex;vertical-align:middle}
|
|
287
|
-
.mini-decay{display:inline-flex;align-items:center;gap:6px;width:100%}
|
|
288
|
-
.mini-decay-bar{flex:1;height:4px;border-radius:2px;background:rgba(255,255,255,.06);overflow:hidden;min-width:30px}
|
|
289
|
-
.mini-decay-fill{height:100%;border-radius:2px}
|
|
290
|
-
.mini-decay-time{color:var(--text-dim);font-size:.7rem;min-width:38px;text-align:right}
|
|
291
|
-
|
|
292
|
-
/* Empty states */
|
|
293
|
-
.empty{color:var(--text-dim);font-size:.86rem;font-style:italic;padding:8px 0}
|
|
294
|
-
.empty-cta{margin-top:6px;display:block;font-style:normal;font-family:var(--font-mono);font-size:.78rem;color:var(--accent-bright)}
|
|
295
|
-
|
|
296
|
-
/* Footer */
|
|
297
|
-
.foot{margin-top:24px;text-align:center;color:var(--text-dim);font-size:.72rem;font-family:var(--font-mono)}
|
|
298
|
-
.foot a{color:var(--accent-bright);text-decoration:none}
|
|
299
|
-
.foot a:hover{text-decoration:underline}
|
|
300
|
-
|
|
301
|
-
/* Scrollbar */
|
|
302
|
-
::-webkit-scrollbar{width:6px;height:6px}
|
|
303
|
-
::-webkit-scrollbar-track{background:transparent}
|
|
304
|
-
::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.08);border-radius:3px}
|
|
305
|
-
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.15)}
|
|
306
|
-
|
|
307
|
-
/* Print */
|
|
308
|
-
@media print{
|
|
309
|
-
.blob,.header-right{display:none}
|
|
310
|
-
.header{position:static}
|
|
311
|
-
body{background:#fff;color:#000}
|
|
312
|
-
}
|
|
313
|
-
</style>
|
|
314
|
-
</head>
|
|
315
|
-
<body>
|
|
316
|
-
|
|
317
|
-
<!-- Shared SVG gradient definition (referenced by the neon icons) -->
|
|
318
|
-
<svg class="svg-defs" aria-hidden="true" focusable="false">
|
|
319
|
-
<defs>
|
|
320
|
-
<linearGradient id="neon-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
321
|
-
<stop offset="0%" stop-color="#00D1FF"/>
|
|
322
|
-
<stop offset="100%" stop-color="#a855f7"/>
|
|
323
|
-
</linearGradient>
|
|
324
|
-
</defs>
|
|
325
|
-
</svg>
|
|
326
|
-
|
|
327
|
-
<div class="blob blob-1"></div>
|
|
328
|
-
<div class="blob blob-2"></div>
|
|
329
|
-
<div class="blob blob-3"></div>
|
|
330
|
-
|
|
331
|
-
<!-- Preact mounts the entire UI here; see src/dashboard-client/main.js -->
|
|
332
|
-
<div id="app"></div>
|
|
333
|
-
|
|
334
|
-
<script>window.__QRING__=Object.freeze({token:${jsString(token)}});</script>
|
|
335
|
-
<script>${DASHBOARD_CLIENT}</script>
|
|
336
|
-
</body>
|
|
337
|
-
</html>`;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// src/core/dashboard.ts
|
|
341
|
-
var AUDIT_WINDOW_SECONDS = 24 * 60 * 60;
|
|
342
|
-
function toSecretSnapshot(entry) {
|
|
343
|
-
const envelope = entry.envelope;
|
|
344
|
-
const decay = envelope ? checkDecay(envelope) : {
|
|
345
|
-
isExpired: false,
|
|
346
|
-
isStale: false,
|
|
347
|
-
lifetimePercent: 0,
|
|
348
|
-
secondsRemaining: null,
|
|
349
|
-
timeRemaining: null
|
|
350
|
-
};
|
|
351
|
-
return {
|
|
352
|
-
key: entry.key,
|
|
353
|
-
scope: entry.scope,
|
|
354
|
-
type: envelope?.states ? "superposition" : "collapsed",
|
|
355
|
-
environments: envelope?.states ? Object.keys(envelope.states) : void 0,
|
|
356
|
-
defaultEnv: envelope?.defaultEnv,
|
|
357
|
-
decay,
|
|
358
|
-
accessCount: envelope?.meta.accessCount ?? 0,
|
|
359
|
-
lastAccessedAt: envelope?.meta.lastAccessedAt,
|
|
360
|
-
createdAt: envelope?.meta.createdAt ?? "",
|
|
361
|
-
updatedAt: envelope?.meta.updatedAt ?? "",
|
|
362
|
-
description: envelope?.meta.description,
|
|
363
|
-
tags: envelope?.meta.tags,
|
|
364
|
-
entangled: envelope?.meta.entangled,
|
|
365
|
-
provider: envelope?.meta.provider,
|
|
366
|
-
requiresApproval: envelope?.meta.requiresApproval,
|
|
367
|
-
jitProvider: envelope?.meta.jitProvider,
|
|
368
|
-
hasRotationFormat: !!envelope?.meta.rotationFormat
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
function summariseHookMatch(match) {
|
|
372
|
-
const parts = [];
|
|
373
|
-
if (match.key) parts.push(`key=${match.key}`);
|
|
374
|
-
if (match.keyPattern) parts.push(`pattern=${match.keyPattern}`);
|
|
375
|
-
if (match.tag) parts.push(`tag=${match.tag}`);
|
|
376
|
-
if (match.scope) parts.push(`scope=${match.scope}`);
|
|
377
|
-
if (match.action?.length) parts.push(`on=${match.action.join("|")}`);
|
|
378
|
-
return parts.length ? parts.join(" \xB7 ") : "any change";
|
|
379
|
-
}
|
|
380
|
-
function buildManifest(projectPath, secrets) {
|
|
381
|
-
const config = readProjectConfig(projectPath);
|
|
382
|
-
if (!config?.secrets) return null;
|
|
383
|
-
const declared = Object.keys(config.secrets);
|
|
384
|
-
const projectSecrets = new Map(
|
|
385
|
-
secrets.filter((s) => s.scope === "project").map((s) => [s.key, s])
|
|
386
|
-
);
|
|
387
|
-
const required = [];
|
|
388
|
-
const missing = [];
|
|
389
|
-
const expired = [];
|
|
390
|
-
const stale = [];
|
|
391
|
-
for (const key of declared) {
|
|
392
|
-
const entry = config.secrets[key];
|
|
393
|
-
if (entry.required) required.push(key);
|
|
394
|
-
const present = projectSecrets.get(key);
|
|
395
|
-
if (!present) {
|
|
396
|
-
if (entry.required) missing.push(key);
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
if (present.decay.isExpired) expired.push(key);
|
|
400
|
-
else if (present.decay.isStale) stale.push(key);
|
|
401
|
-
}
|
|
402
|
-
return {
|
|
403
|
-
declared: declared.length,
|
|
404
|
-
required: required.length,
|
|
405
|
-
missing,
|
|
406
|
-
expired,
|
|
407
|
-
stale
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
function buildPolicySnapshot(projectPath) {
|
|
411
|
-
const summary = getPolicySummary(projectPath);
|
|
412
|
-
const mcp = summary.details.mcp ?? {};
|
|
413
|
-
const exec = summary.details.exec ?? {};
|
|
414
|
-
const sec = summary.details.secrets ?? {};
|
|
415
|
-
return {
|
|
416
|
-
hasMcpPolicy: summary.hasMcpPolicy,
|
|
417
|
-
hasExecPolicy: summary.hasExecPolicy,
|
|
418
|
-
hasSecretPolicy: summary.hasSecretPolicy,
|
|
419
|
-
counts: {
|
|
420
|
-
allowTools: mcp.allowTools?.length ?? 0,
|
|
421
|
-
denyTools: mcp.denyTools?.length ?? 0,
|
|
422
|
-
deniedKeys: mcp.deniedKeys?.length ?? 0,
|
|
423
|
-
deniedTags: mcp.deniedTags?.length ?? 0,
|
|
424
|
-
allowCommands: exec.allowCommands?.length ?? 0,
|
|
425
|
-
denyCommands: exec.denyCommands?.length ?? 0,
|
|
426
|
-
requireApprovalForTags: sec.requireApprovalForTags?.length ?? 0,
|
|
427
|
-
requireRotationFormatForTags: sec.requireRotationFormatForTags?.length ?? 0
|
|
428
|
-
},
|
|
429
|
-
maxTtlSeconds: sec.maxTtlSeconds,
|
|
430
|
-
maxRuntimeSeconds: exec.maxRuntimeSeconds
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
function buildAuditMetrics(events) {
|
|
434
|
-
const byAction = {};
|
|
435
|
-
const bySource = {};
|
|
436
|
-
const readCounts = /* @__PURE__ */ new Map();
|
|
437
|
-
for (const e of events) {
|
|
438
|
-
byAction[e.action] = (byAction[e.action] ?? 0) + 1;
|
|
439
|
-
bySource[e.source] = (bySource[e.source] ?? 0) + 1;
|
|
440
|
-
if (e.action === "read" && e.key) {
|
|
441
|
-
readCounts.set(e.key, (readCounts.get(e.key) ?? 0) + 1);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const topRead = [...readCounts.entries()].map(([key, reads]) => ({ key, reads })).sort((a, b) => b.reads - a.reads).slice(0, 10);
|
|
445
|
-
return {
|
|
446
|
-
byAction,
|
|
447
|
-
bySource,
|
|
448
|
-
topRead,
|
|
449
|
-
total: events.length,
|
|
450
|
-
windowSeconds: AUDIT_WINDOW_SECONDS
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
function collectSnapshot() {
|
|
454
|
-
const projectPath = process.cwd();
|
|
455
|
-
const entries = listSecrets({ source: "api", silent: true, projectPath });
|
|
456
|
-
const secrets = entries.map(toSecretSnapshot);
|
|
457
|
-
let healthy = 0;
|
|
458
|
-
let stale = 0;
|
|
459
|
-
let expired = 0;
|
|
460
|
-
let noDecay = 0;
|
|
461
|
-
let protectedCount = 0;
|
|
462
|
-
const scopes = { global: 0, project: 0, team: 0, org: 0 };
|
|
463
|
-
for (const s of secrets) {
|
|
464
|
-
if (!s.decay.timeRemaining) noDecay++;
|
|
465
|
-
else if (s.decay.isExpired) expired++;
|
|
466
|
-
else if (s.decay.isStale) stale++;
|
|
467
|
-
else healthy++;
|
|
468
|
-
if (s.requiresApproval) protectedCount++;
|
|
469
|
-
if (s.scope === "global") scopes.global++;
|
|
470
|
-
else if (s.scope === "project") scopes.project++;
|
|
471
|
-
else if (s.scope === "team") scopes.team++;
|
|
472
|
-
else if (s.scope === "org") scopes.org++;
|
|
473
|
-
}
|
|
474
|
-
const auditWindow = queryAudit({
|
|
475
|
-
since: new Date(Date.now() - AUDIT_WINDOW_SECONDS * 1e3).toISOString()
|
|
476
|
-
}).filter((e) => e.action !== "list");
|
|
477
|
-
const recent = auditWindow.slice(0, 80);
|
|
478
|
-
const approvals = listApprovals().map((a) => ({
|
|
479
|
-
id: a.id,
|
|
480
|
-
key: a.key,
|
|
481
|
-
scope: a.scope,
|
|
482
|
-
reason: a.reason,
|
|
483
|
-
grantedBy: a.grantedBy,
|
|
484
|
-
grantedAt: a.grantedAt,
|
|
485
|
-
expiresAt: a.expiresAt,
|
|
486
|
-
secondsRemaining: Math.floor(
|
|
487
|
-
(new Date(a.expiresAt).getTime() - Date.now()) / 1e3
|
|
488
|
-
),
|
|
489
|
-
valid: a.valid && !a.tampered,
|
|
490
|
-
tampered: a.tampered
|
|
491
|
-
}));
|
|
492
|
-
const hookEntries = listHooks().map((h) => ({
|
|
493
|
-
id: h.id,
|
|
494
|
-
type: h.type,
|
|
495
|
-
description: h.description,
|
|
496
|
-
enabled: h.enabled,
|
|
497
|
-
match: h.match,
|
|
498
|
-
matchSummary: summariseHookMatch(h.match)
|
|
499
|
-
}));
|
|
500
|
-
return {
|
|
501
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
502
|
-
version: PACKAGE_VERSION,
|
|
503
|
-
projectPath,
|
|
504
|
-
secrets,
|
|
505
|
-
health: { healthy, stale, expired, noDecay, total: secrets.length },
|
|
506
|
-
scopes,
|
|
507
|
-
protectedCount,
|
|
508
|
-
entanglements: listEntanglements(),
|
|
509
|
-
tunnels: tunnelList(),
|
|
510
|
-
audit: recent,
|
|
511
|
-
auditMetrics: buildAuditMetrics(auditWindow),
|
|
512
|
-
anomalies: detectAnomalies(),
|
|
513
|
-
environment: collapseEnvironment({ projectPath }),
|
|
514
|
-
manifest: buildManifest(projectPath, secrets),
|
|
515
|
-
policy: buildPolicySnapshot(projectPath),
|
|
516
|
-
approvals,
|
|
517
|
-
hooks: hookEntries,
|
|
518
|
-
memoryKeys: listMemory().length,
|
|
519
|
-
auditChain: (() => {
|
|
520
|
-
const chain = verifyAuditChain();
|
|
521
|
-
return {
|
|
522
|
-
intact: chain.intact,
|
|
523
|
-
totalEvents: chain.totalEvents,
|
|
524
|
-
validEvents: chain.validEvents,
|
|
525
|
-
...chain.brokenAt != null ? { brokenAt: chain.brokenAt } : {}
|
|
526
|
-
};
|
|
527
|
-
})()
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
var SECURITY_HEADERS = {
|
|
531
|
-
"Content-Security-Policy": "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'",
|
|
532
|
-
"X-Frame-Options": "DENY",
|
|
533
|
-
"X-Content-Type-Options": "nosniff",
|
|
534
|
-
"Referrer-Policy": "no-referrer",
|
|
535
|
-
"Cache-Control": "no-store"
|
|
536
|
-
};
|
|
537
|
-
function timingSafeStringEqual(a, b) {
|
|
538
|
-
const ab = Buffer.from(a, "utf8");
|
|
539
|
-
const bb = Buffer.from(b, "utf8");
|
|
540
|
-
if (ab.length !== bb.length) return false;
|
|
541
|
-
return timingSafeEqual(ab, bb);
|
|
542
|
-
}
|
|
543
|
-
function startDashboardServer(options = {}) {
|
|
544
|
-
const port = options.port ?? 9876;
|
|
545
|
-
const clients = /* @__PURE__ */ new Set();
|
|
546
|
-
let intervalHandle = null;
|
|
547
|
-
const token = randomBytes(24).toString("base64url");
|
|
548
|
-
const html = getDashboardHtml(token);
|
|
549
|
-
function broadcast() {
|
|
550
|
-
const snapshot = collectSnapshot();
|
|
551
|
-
const data = `data: ${JSON.stringify(snapshot)}
|
|
552
|
-
|
|
553
|
-
`;
|
|
554
|
-
for (const res of clients) {
|
|
555
|
-
if (res.writableEnded || res.destroyed) {
|
|
556
|
-
clients.delete(res);
|
|
557
|
-
continue;
|
|
558
|
-
}
|
|
559
|
-
try {
|
|
560
|
-
const ok = res.write(data);
|
|
561
|
-
if (!ok) {
|
|
562
|
-
clients.delete(res);
|
|
563
|
-
try {
|
|
564
|
-
res.end();
|
|
565
|
-
} catch {
|
|
566
|
-
try {
|
|
567
|
-
res.destroy();
|
|
568
|
-
} catch {
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
} catch {
|
|
573
|
-
clients.delete(res);
|
|
574
|
-
try {
|
|
575
|
-
res.end();
|
|
576
|
-
} catch {
|
|
577
|
-
try {
|
|
578
|
-
res.destroy();
|
|
579
|
-
} catch {
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
const server = createServer((req, res) => {
|
|
586
|
-
let pathname;
|
|
587
|
-
let query;
|
|
588
|
-
try {
|
|
589
|
-
const parsed = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
590
|
-
pathname = parsed.pathname;
|
|
591
|
-
query = parsed.searchParams;
|
|
592
|
-
} catch {
|
|
593
|
-
res.writeHead(400, { ...SECURITY_HEADERS, "Content-Type": "text/plain; charset=utf-8" });
|
|
594
|
-
res.end("Bad Request: invalid URL");
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
const provided = query.get("token") ?? "";
|
|
598
|
-
if (!timingSafeStringEqual(provided, token)) {
|
|
599
|
-
res.writeHead(403, { ...SECURITY_HEADERS, "Content-Type": "text/plain; charset=utf-8" });
|
|
600
|
-
res.end("Forbidden: missing or invalid token");
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
if (pathname === "/events") {
|
|
604
|
-
res.writeHead(200, {
|
|
605
|
-
...SECURITY_HEADERS,
|
|
606
|
-
"Content-Type": "text/event-stream",
|
|
607
|
-
"Cache-Control": "no-cache",
|
|
608
|
-
Connection: "keep-alive"
|
|
609
|
-
});
|
|
610
|
-
const snapshot = collectSnapshot();
|
|
611
|
-
res.write(`data: ${JSON.stringify(snapshot)}
|
|
612
|
-
|
|
613
|
-
`);
|
|
614
|
-
clients.add(res);
|
|
615
|
-
req.on("close", () => clients.delete(res));
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
if (pathname === "/api/status") {
|
|
619
|
-
const snapshot = collectSnapshot();
|
|
620
|
-
res.writeHead(200, {
|
|
621
|
-
...SECURITY_HEADERS,
|
|
622
|
-
"Content-Type": "application/json"
|
|
623
|
-
});
|
|
624
|
-
res.end(JSON.stringify(snapshot, null, 2));
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
res.writeHead(200, { ...SECURITY_HEADERS, "Content-Type": "text/html; charset=utf-8" });
|
|
628
|
-
res.end(html);
|
|
629
|
-
});
|
|
630
|
-
server.listen(port, "127.0.0.1", () => {
|
|
631
|
-
intervalHandle = setInterval(broadcast, 5e3);
|
|
632
|
-
if (intervalHandle && typeof intervalHandle === "object" && "unref" in intervalHandle) {
|
|
633
|
-
intervalHandle.unref();
|
|
634
|
-
}
|
|
635
|
-
});
|
|
636
|
-
return {
|
|
637
|
-
port,
|
|
638
|
-
token,
|
|
639
|
-
url: `http://127.0.0.1:${port}/?token=${token}`,
|
|
640
|
-
close: () => {
|
|
641
|
-
if (intervalHandle) clearInterval(intervalHandle);
|
|
642
|
-
for (const res of clients) {
|
|
643
|
-
try {
|
|
644
|
-
res.end();
|
|
645
|
-
} catch {
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
clients.clear();
|
|
649
|
-
server.close();
|
|
650
|
-
},
|
|
651
|
-
server
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
export {
|
|
655
|
-
collectSnapshot,
|
|
656
|
-
startDashboardServer
|
|
657
|
-
};
|
|
658
|
-
//# sourceMappingURL=dashboard-A3GJQCJX.js.map
|