diff --git a/dashboard/src/main.tsx b/dashboard/src/main.tsx index e2b56ea..15c6621 100644 --- a/dashboard/src/main.tsx +++ b/dashboard/src/main.tsx @@ -1767,7 +1767,7 @@ function WebhookPage({ ]; return (
- } title="GitHub webhooks" subtitle={summary?.mode === "canary" ? "Canary ingestion health. Only enabled repositories may create jobs." : "Shadow ingestion health. Deliveries are observed but do not create jobs."} action={} /> + } title="GitHub webhooks" subtitle={summary?.mode === "primary" ? "Primary webhook ingestion. IMAP remains active as an idempotent safety net." : summary?.mode === "canary" ? "Canary ingestion health. Only enabled repositories may create jobs." : "Shadow ingestion health. Deliveries are observed but do not create jobs."} action={} /> {error ? : null}
{sections.map((item) => )} diff --git a/docs/ingestion.md b/docs/ingestion.md index 9c65096..add0f61 100644 --- a/docs/ingestion.md +++ b/docs/ingestion.md @@ -145,5 +145,26 @@ row makes the queue operation idempotent, and the retry repairs the monitoring receipt. `edited` comments/reviews, unsupported families, and repositories outside `enabledRepos` remain observational only. +## Primary webhook with stable IMAP fallback + +After the dashboard gate has no unexplained IMAP-only actionable events, set +both `GITHUB_AGENT_BRIDGE_WEBHOOK_MODE=primary` and +`GITHUB_AGENT_BRIDGE_WEBHOOK_PRIMARY_ACK=true`. The second switch is a deliberate +operator acknowledgement; `primary` fails closed without it. The configured +policy remains authoritative for trust, action and routing decisions. + +Primary changes which source is expected to win, not the idempotency model. +Keep the IMAP reader enabled during the stable fallback phase. If webhook +delivery is late or unavailable, email still creates the canonical event and +job; if both arrive, the unique event key links the second receipt to the first +job. Rollback is configuration-only: return the endpoint to `shadow`, leave the +IMAP reader running, and inspect the exception queue before trying primary +again. Do not enable `--mark-seen` merely because primary mode is active. + +This implementation does not add an arbitrary sleep to IMAP. Delaying the +reader would also delay genuine webhook gaps and complicate its durable UID +cursor. The first-source metrics make the actual winner visible, while the +shared transaction guarantees correctness independently of arrival order. + Webhook enqueueing must not be enabled until recovery of persisted-but- unprocessed receipts and divergence metrics have been validated in production. diff --git a/docs/webhook-events.md b/docs/webhook-events.md index c8243fe..13cc248 100644 --- a/docs/webhook-events.md +++ b/docs/webhook-events.md @@ -8,16 +8,16 @@ planning a new integration. Last reviewed: 2026-10-02. Support levels: -- **Canonical shadow**: persisted with an immutable canonical event key and - eligible for IMAP/webhook coverage comparison. It never creates a job in - Phase 1. +- **Canonical**: persisted with an immutable canonical event key and eligible + for IMAP/webhook coverage comparison. It is observational in shadow mode and + may enqueue in canary/primary mode when policy permits it. - **Observed only**: a signed delivery can be persisted as `unsupported`, but no canonical key is derived. - **Not selected**: operators should not subscribe to it in Phase 1. | Support | GitHub event names | | --- | --- | -| Canonical shadow | `commit_comment`, `issue_comment`, `pull_request_review`, `pull_request_review_comment`, `workflow_run` | +| Canonical | `commit_comment`, `issue_comment`, `pull_request_review`, `pull_request_review_comment`, `workflow_run` | | Observed only / not selected | `branch_protection_configuration`, `branch_protection_rule`, `check_run`, `check_suite`, `code_scanning_alert`, `create`, `custom_property`, `custom_property_values`, `delete`, `dependabot_alert`, `deploy_key`, `deployment`, `deployment_protection_rule`, `deployment_review`, `deployment_status`, `discussion`, `discussion_comment`, `fork`, `github_app_authorization`, `gollum`, `installation`, `installation_repositories`, `installation_target`, `issue_dependencies`, `issue_relates_to`, `issues`, `label`, `marketplace_purchase`, `member`, `membership`, `merge_group`, `meta`, `milestone`, `org_block`, `organization`, `package`, `page_build`, `personal_access_token_request`, `ping`, `project`, `project_card`, `project_column`, `projects_v2`, `projects_v2_item`, `projects_v2_status_update`, `public`, `pull_request`, `pull_request_review_thread`, `push`, `registry_package`, `release`, `repository`, `repository_advisory`, `repository_dispatch`, `repository_import`, `repository_ruleset`, `repository_vulnerability_alert`, `secret_scanning_alert`, `secret_scanning_alert_location`, `secret_scanning_scan`, `security_advisory`, `security_and_analysis`, `sponsorship`, `star`, `status`, `sub_issues`, `team`, `team_add`, `watch`, `workflow_dispatch`, `workflow_job` | The inventory names event families, not every `action` value. Actions are diff --git a/src/github_agent_bridge/backend.py b/src/github_agent_bridge/backend.py index 1656803..17eafed 100644 --- a/src/github_agent_bridge/backend.py +++ b/src/github_agent_bridge/backend.py @@ -239,6 +239,7 @@ def __init__( webhook_retention_days: int | None = None, webhook_mode: str | None = None, webhook_policy: str | Path | None = None, + webhook_primary_ack: bool | None = None, ) -> None: self.db = Path(db).expanduser() self.secret_key = secret_key or os.getenv("GITHUB_AGENT_BRIDGE_DASHBOARD_SECRET_KEY", "") @@ -263,12 +264,19 @@ def __init__( self.webhook_max_bytes = webhook_max_bytes or int(os.getenv("GITHUB_AGENT_BRIDGE_WEBHOOK_MAX_BYTES", "1048576")) self.webhook_retention_days = webhook_retention_days or int(os.getenv("GITHUB_AGENT_BRIDGE_WEBHOOK_RETENTION_DAYS", "30")) self.webhook_mode = (webhook_mode or os.getenv("GITHUB_AGENT_BRIDGE_WEBHOOK_MODE", "shadow")).lower() - if self.webhook_mode not in {"shadow", "canary"}: - raise ValueError("GITHUB_AGENT_BRIDGE_WEBHOOK_MODE must be shadow or canary") + if self.webhook_mode not in {"shadow", "canary", "primary"}: + raise ValueError("GITHUB_AGENT_BRIDGE_WEBHOOK_MODE must be shadow, canary, or primary") policy_value = webhook_policy or os.getenv("GITHUB_AGENT_BRIDGE_WEBHOOK_POLICY", "") self.webhook_policy = Path(policy_value).expanduser() if policy_value else None - if self.webhook_mode == "canary" and self.webhook_policy is None: - raise ValueError("GITHUB_AGENT_BRIDGE_WEBHOOK_POLICY is required in canary mode") + if self.webhook_mode != "shadow" and self.webhook_policy is None: + raise ValueError("GITHUB_AGENT_BRIDGE_WEBHOOK_POLICY is required outside shadow mode") + self.webhook_primary_ack = ( + webhook_primary_ack + if webhook_primary_ack is not None + else os.getenv("GITHUB_AGENT_BRIDGE_WEBHOOK_PRIMARY_ACK", "").lower() in {"1", "true", "yes"} + ) + if self.webhook_mode == "primary" and not self.webhook_primary_ack: + raise ValueError("primary webhook mode requires GITHUB_AGENT_BRIDGE_WEBHOOK_PRIMARY_ACK=true") @property def oauth_ready(self) -> bool: @@ -778,13 +786,13 @@ async def github_webhook_shadow(request: Request) -> dict[str, Any]: ensure_webhook_schema() enqueue_status = None job_id = None - if config.webhook_mode == "canary": + if config.webhook_mode in {"canary", "primary"}: policy = Policy.from_file(config.webhook_policy) notification = webhook_notification(event_name, delivery_id, payload) repo = str(full_name or "").lower() if notification is None: enqueue_status = "ignored" - elif repo not in policy.enabled_repos: + elif config.webhook_mode == "canary" and repo not in policy.enabled_repos: enqueue_status = "outside_canary" else: job, enqueue_status = JobQueue(config.db).ingest( diff --git a/src/github_agent_bridge/dashboard_static/assets/index-DbrBVlog.js b/src/github_agent_bridge/dashboard_static/assets/index-DHTaiUxP.js similarity index 89% rename from src/github_agent_bridge/dashboard_static/assets/index-DbrBVlog.js rename to src/github_agent_bridge/dashboard_static/assets/index-DHTaiUxP.js index 8276e51..b4a995d 100644 --- a/src/github_agent_bridge/dashboard_static/assets/index-DbrBVlog.js +++ b/src/github_agent_bridge/dashboard_static/assets/index-DHTaiUxP.js @@ -175,7 +175,7 @@ var ea=e=>{throw TypeError(e)};var $r=(e,t,n)=>t.has(e)||ea("Cannot "+n);var g=( `}),n.push(e[r]);return t&&e.length>0&&n.push({type:"text",value:` `}),n}function Ha(e){let t=0,n=e.charCodeAt(t);for(;n===9||n===32;)t++,n=e.charCodeAt(t);return e.slice(t)}function Ka(e,t){const n=Wp(e,t),r=n.one(e,void 0),s=Dp(n),a=Array.isArray(r)?{type:"root",children:r}:r||{type:"root",children:[]};return s&&a.children.push({type:"text",value:` `},s),a}function Zp(e,t){return e&&"run"in e?async function(n,r){const s=Ka(n,{file:r,...t});await e.run(s,r)}:function(n,r){return Ka(n,{file:r,...e||t})}}function Qa(e){if(e)throw e}var Jr,Va;function em(){if(Va)return Jr;Va=1;var e=Object.prototype.hasOwnProperty,t=Object.prototype.toString,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,s=function(c){return typeof Array.isArray=="function"?Array.isArray(c):t.call(c)==="[object Array]"},a=function(c){if(!c||t.call(c)!=="[object Object]")return!1;var d=e.call(c,"constructor"),h=c.constructor&&c.constructor.prototype&&e.call(c.constructor.prototype,"isPrototypeOf");if(c.constructor&&!d&&!h)return!1;var m;for(m in c);return typeof m>"u"||e.call(c,m)},o=function(c,d){n&&d.name==="__proto__"?n(c,d.name,{enumerable:!0,configurable:!0,value:d.newValue,writable:!0}):c[d.name]=d.newValue},l=function(c,d){if(d==="__proto__")if(e.call(c,d)){if(r)return r(c,d).value}else return;return c[d]};return Jr=function u(){var c,d,h,m,p,y,w=arguments[0],j=1,b=arguments.length,S=!1;for(typeof w=="boolean"&&(S=w,w=arguments[1]||{},j=2),(w==null||typeof w!="object"&&typeof w!="function")&&(w={});jo.length;let u;l&&o.push(s);try{u=e.apply(this,o)}catch(c){const d=c;if(l&&n)throw d;return s(d)}l||(u&&u.then&&typeof u.then=="function"?u.then(a,s):u instanceof Error?s(u):a(u))}function s(o,...l){n||(n=!0,t(o,...l))}function a(o){s(null,o)}}const rt={basename:im,dirname:sm,extname:am,join:om,sep:"/"};function im(e,t){if(t!==void 0&&typeof t!="string")throw new TypeError('"ext" argument must be a string');dr(e);let n=0,r=-1,s=e.length,a;if(t===void 0||t.length===0||t.length>e.length){for(;s--;)if(e.codePointAt(s)===47){if(a){n=s+1;break}}else r<0&&(a=!0,r=s+1);return r<0?"":e.slice(n,r)}if(t===e)return"";let o=-1,l=t.length-1;for(;s--;)if(e.codePointAt(s)===47){if(a){n=s+1;break}}else o<0&&(a=!0,o=s+1),l>-1&&(e.codePointAt(s)===t.codePointAt(l--)?l<0&&(r=s):(l=-1,r=o));return n===r?r=o:r<0&&(r=e.length),e.slice(n,r)}function sm(e){if(dr(e),e.length===0)return".";let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||(r=!0);return t<0?e.codePointAt(0)===47?"/":".":t===1&&e.codePointAt(0)===47?"//":e.slice(0,t)}function am(e){dr(e);let t=e.length,n=-1,r=0,s=-1,a=0,o;for(;t--;){const l=e.codePointAt(t);if(l===47){if(o){r=t+1;break}continue}n<0&&(o=!0,n=t+1),l===46?s<0?s=t:a!==1&&(a=1):s>-1&&(a=-1)}return s<0||n<0||a===0||a===1&&s===n-1&&s===r+1?"":e.slice(s,n)}function om(...e){let t=-1,n;for(;++t0&&e.codePointAt(e.length-1)===47&&(n+="/"),t?"/"+n:n}function um(e,t){let n="",r=0,s=-1,a=0,o=-1,l,u;for(;++o<=e.length;){if(o2){if(u=n.lastIndexOf("/"),u!==n.length-1){u<0?(n="",r=0):(n=n.slice(0,u),r=n.length-1-n.lastIndexOf("/")),s=o,a=0;continue}}else if(n.length>0){n="",r=0,s=o,a=0;continue}}t&&(n=n.length>0?n+"/..":"..",r=2)}else n.length>0?n+="/"+e.slice(s+1,o):n=e.slice(s+1,o),r=o-s-1;s=o,a=0}else l===46&&a>-1?a++:a=-1}return n}function dr(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}const cm={cwd:dm};function dm(){return"/"}function Ai(e){return!!(e!==null&&typeof e=="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}function hm(e){if(typeof e=="string")e=new URL(e);else if(!Ai(e)){const t=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.protocol!=="file:"){const t=new TypeError("The URL must be of scheme file");throw t.code="ERR_INVALID_URL_SCHEME",t}return pm(e)}function pm(e){if(e.hostname!==""){const r=new TypeError('File URL host must be "localhost" or empty on darwin');throw r.code="ERR_INVALID_FILE_URL_HOST",r}const t=e.pathname;let n=-1;for(;++n0){let[p,...y]=d;const w=r[m][1];Ti(w)&&Ti(p)&&(p=Xr(!0,w,p)),r[m]=[c,p,...y]}}}}const gm=new is().freeze();function ti(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `parser`")}function ni(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `compiler`")}function ri(e,t){if(t)throw new Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Ga(e){if(!Ti(e)||typeof e.type!="string")throw new TypeError("Expected node, got `"+e+"`")}function Ja(e,t,n){if(!n)throw new Error("`"+e+"` finished async. Use `"+t+"` instead")}function Nr(e){return bm(e)?e:new _l(e)}function bm(e){return!!(e&&typeof e=="object"&&"message"in e&&"messages"in e)}function ym(e){return typeof e=="string"||wm(e)}function wm(e){return!!(e&&typeof e=="object"&&"byteLength"in e&&"byteOffset"in e)}const vm="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",Xa=[],Ya={allowDangerousHtml:!0},jm=/^(https?|ircs?|mailto|xmpp)$/i,km=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"className",id:"remove-classname"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function Nm(e){const t=Sm(e),n=Cm(e);return _m(t.runSync(t.parse(n),n),e)}function Sm(e){const t=e.rehypePlugins||Xa,n=e.remarkPlugins||Xa,r=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...Ya}:Ya;return gm().use(rp).use(n).use(Zp,r).use(t)}function Cm(e){const t=e.children||"",n=new _l;return typeof t=="string"&&(n.value=t),n}function _m(e,t){const n=t.allowedElements,r=t.allowElement,s=t.components,a=t.disallowedElements,o=t.skipHtml,l=t.unwrapDisallowed,u=t.urlTransform||Em;for(const d of km)Object.hasOwn(t,d.from)&&(""+d.from+(d.to?"use `"+d.to+"` instead":"remove it")+vm+d.id,void 0);return Cl(e,c),Oc(e,{Fragment:i.Fragment,components:s,ignoreInvalidStyle:!0,jsx:i.jsx,jsxs:i.jsxs,passKeys:!0,passNode:!0});function c(d,h,m){if(d.type==="raw"&&m&&typeof h=="number")return o?m.children.splice(h,1):m.children[h]={type:"text",value:d.value},h;if(d.type==="element"){let p;for(p in Vr)if(Object.hasOwn(Vr,p)&&Object.hasOwn(d.properties,p)){const y=d.properties[p],w=Vr[p];(w===null||w.includes(d.tagName))&&(d.properties[p]=u(String(y||""),p,d))}}if(d.type==="element"){let p=n?!n.includes(d.tagName):a?a.includes(d.tagName):!1;if(!p&&r&&typeof h=="number"&&(p=!r(d,h,m)),p&&m&&typeof h=="number")return l&&d.children?m.children.splice(h,1,...d.children):m.children.splice(h,1),h}}}function Em(e){const t=e.indexOf(":"),n=e.indexOf("?"),r=e.indexOf("#"),s=e.indexOf("/");return t===-1||s!==-1&&t>s||n!==-1&&t>n||r!==-1&&t>r||jm.test(e.slice(0,t))?e:""}const ss="-",Pm=e=>{const t=Im(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:o=>{const l=o.split(ss);return l[0]===""&&l.length!==1&&l.shift(),El(l,t)||Rm(o)},getConflictingClassGroupIds:(o,l)=>{const u=n[o]||[];return l&&r[o]?[...u,...r[o]]:u}}},El=(e,t)=>{var o;if(e.length===0)return t.classGroupId;const n=e[0],r=t.nextPart.get(n),s=r?El(e.slice(1),r):void 0;if(s)return s;if(t.validators.length===0)return;const a=e.join(ss);return(o=t.validators.find(({validator:l})=>l(a)))==null?void 0:o.classGroupId},Za=/^\[(.+)\]$/,Rm=e=>{if(Za.test(e)){const t=Za.exec(e)[1],n=t==null?void 0:t.substring(0,t.indexOf(":"));if(n)return"arbitrary.."+n}},Im=e=>{const{theme:t,prefix:n}=e,r={nextPart:new Map,validators:[]};return Am(Object.entries(e.classGroups),n).forEach(([a,o])=>{Li(o,r,a,t)}),r},Li=(e,t,n,r)=>{e.forEach(s=>{if(typeof s=="string"){const a=s===""?t:eo(t,s);a.classGroupId=n;return}if(typeof s=="function"){if(Tm(s)){Li(s(r),t,n,r);return}t.validators.push({validator:s,classGroupId:n});return}Object.entries(s).forEach(([a,o])=>{Li(o,eo(t,a),n,r)})})},eo=(e,t)=>{let n=e;return t.split(ss).forEach(r=>{n.nextPart.has(r)||n.nextPart.set(r,{nextPart:new Map,validators:[]}),n=n.nextPart.get(r)}),n},Tm=e=>e.isThemeGetter,Am=(e,t)=>t?e.map(([n,r])=>{const s=r.map(a=>typeof a=="string"?t+a:typeof a=="object"?Object.fromEntries(Object.entries(a).map(([o,l])=>[t+o,l])):a);return[n,s]}):e,Lm=e=>{if(e<1)return{get:()=>{},set:()=>{}};let t=0,n=new Map,r=new Map;const s=(a,o)=>{n.set(a,o),t++,t>e&&(t=0,r=n,n=new Map)};return{get(a){let o=n.get(a);if(o!==void 0)return o;if((o=r.get(a))!==void 0)return s(a,o),o},set(a,o){n.has(a)?n.set(a,o):s(a,o)}}},Pl="!",Mm=e=>{const{separator:t,experimentalParseClassName:n}=e,r=t.length===1,s=t[0],a=t.length,o=l=>{const u=[];let c=0,d=0,h;for(let j=0;jd?h-d:void 0;return{modifiers:u,hasImportantModifier:p,baseClassName:y,maybePostfixModifierPosition:w}};return n?l=>n({className:l,parseClassName:o}):o},Om=e=>{if(e.length<=1)return e;const t=[];let n=[];return e.forEach(r=>{r[0]==="["?(t.push(...n.sort(),r),n=[]):n.push(r)}),t.push(...n.sort()),t},Dm=e=>({cache:Lm(e.cacheSize),parseClassName:Mm(e),...Pm(e)}),Fm=/\s+/,zm=(e,t)=>{const{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:s}=t,a=[],o=e.trim().split(Fm);let l="";for(let u=o.length-1;u>=0;u-=1){const c=o[u],{modifiers:d,hasImportantModifier:h,baseClassName:m,maybePostfixModifierPosition:p}=n(c);let y=!!p,w=r(y?m.substring(0,p):m);if(!w){if(!y){l=c+(l.length>0?" "+l:l);continue}if(w=r(m),!w){l=c+(l.length>0?" "+l:l);continue}y=!1}const j=Om(d).join(":"),b=h?j+Pl:j,S=b+w;if(a.includes(S))continue;a.push(S);const _=s(w,y);for(let N=0;N<_.length;++N){const q=_[N];a.push(b+q)}l=c+(l.length>0?" "+l:l)}return l};function qm(){let e=0,t,n,r="";for(;e{if(typeof e=="string")return e;let t,n="";for(let r=0;rh(d),e());return n=Dm(c),r=n.cache.get,s=n.cache.set,a=l,l(u)}function l(u){const c=r(u);if(c)return c;const d=zm(u,n);return s(u,d),d}return function(){return a(qm.apply(null,arguments))}}const de=e=>{const t=n=>n[e]||[];return t.isThemeGetter=!0,t},Il=/^\[(?:([a-z-]+):)?(.+)\]$/i,Um=/^\d+\/\d+$/,$m=new Set(["px","full","screen"]),Hm=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Km=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,Qm=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,Vm=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,Wm=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,pt=e=>rn(e)||$m.has(e)||Um.test(e),wt=e=>Nn(e,"length",nf),rn=e=>!!e&&!Number.isNaN(Number(e)),ii=e=>Nn(e,"number",rn),Mn=e=>!!e&&Number.isInteger(Number(e)),Gm=e=>e.endsWith("%")&&rn(e.slice(0,-1)),W=e=>Il.test(e),vt=e=>Hm.test(e),Jm=new Set(["length","size","percentage"]),Xm=e=>Nn(e,Jm,Tl),Ym=e=>Nn(e,"position",Tl),Zm=new Set(["image","url"]),ef=e=>Nn(e,Zm,sf),tf=e=>Nn(e,"",rf),On=()=>!0,Nn=(e,t,n)=>{const r=Il.exec(e);return r?r[1]?typeof t=="string"?r[1]===t:t.has(r[1]):n(r[2]):!1},nf=e=>Km.test(e)&&!Qm.test(e),Tl=()=>!1,rf=e=>Vm.test(e),sf=e=>Wm.test(e),af=()=>{const e=de("colors"),t=de("spacing"),n=de("blur"),r=de("brightness"),s=de("borderColor"),a=de("borderRadius"),o=de("borderSpacing"),l=de("borderWidth"),u=de("contrast"),c=de("grayscale"),d=de("hueRotate"),h=de("invert"),m=de("gap"),p=de("gradientColorStops"),y=de("gradientColorStopPositions"),w=de("inset"),j=de("margin"),b=de("opacity"),S=de("padding"),_=de("saturate"),N=de("scale"),q=de("sepia"),k=de("skew"),B=de("space"),M=de("translate"),v=()=>["auto","contain","none"],F=()=>["auto","hidden","clip","visible","scroll"],L=()=>["auto",W,t],P=()=>[W,t],G=()=>["",pt,wt],z=()=>["auto",rn,W],E=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],O=()=>["solid","dashed","dotted","double","none"],Q=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],he=()=>["start","end","center","between","around","evenly","stretch"],se=()=>["","0",W],f=()=>["auto","avoid","all","avoid-page","page","left","right","column"],ue=()=>[rn,W];return{cacheSize:500,separator:":",theme:{colors:[On],spacing:[pt,wt],blur:["none","",vt,W],brightness:ue(),borderColor:[e],borderRadius:["none","","full",vt,W],borderSpacing:P(),borderWidth:G(),contrast:ue(),grayscale:se(),hueRotate:ue(),invert:se(),gap:P(),gradientColorStops:[e],gradientColorStopPositions:[Gm,wt],inset:L(),margin:L(),opacity:ue(),padding:P(),saturate:ue(),scale:ue(),sepia:se(),skew:ue(),space:P(),translate:P()},classGroups:{aspect:[{aspect:["auto","square","video",W]}],container:["container"],columns:[{columns:[vt]}],"break-after":[{"break-after":f()}],"break-before":[{"break-before":f()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...E(),W]}],overflow:[{overflow:F()}],"overflow-x":[{"overflow-x":F()}],"overflow-y":[{"overflow-y":F()}],overscroll:[{overscroll:v()}],"overscroll-x":[{"overscroll-x":v()}],"overscroll-y":[{"overscroll-y":v()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[w]}],"inset-x":[{"inset-x":[w]}],"inset-y":[{"inset-y":[w]}],start:[{start:[w]}],end:[{end:[w]}],top:[{top:[w]}],right:[{right:[w]}],bottom:[{bottom:[w]}],left:[{left:[w]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Mn,W]}],basis:[{basis:L()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",W]}],grow:[{grow:se()}],shrink:[{shrink:se()}],order:[{order:["first","last","none",Mn,W]}],"grid-cols":[{"grid-cols":[On]}],"col-start-end":[{col:["auto",{span:["full",Mn,W]},W]}],"col-start":[{"col-start":z()}],"col-end":[{"col-end":z()}],"grid-rows":[{"grid-rows":[On]}],"row-start-end":[{row:["auto",{span:[Mn,W]},W]}],"row-start":[{"row-start":z()}],"row-end":[{"row-end":z()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",W]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",W]}],gap:[{gap:[m]}],"gap-x":[{"gap-x":[m]}],"gap-y":[{"gap-y":[m]}],"justify-content":[{justify:["normal",...he()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...he(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...he(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[S]}],px:[{px:[S]}],py:[{py:[S]}],ps:[{ps:[S]}],pe:[{pe:[S]}],pt:[{pt:[S]}],pr:[{pr:[S]}],pb:[{pb:[S]}],pl:[{pl:[S]}],m:[{m:[j]}],mx:[{mx:[j]}],my:[{my:[j]}],ms:[{ms:[j]}],me:[{me:[j]}],mt:[{mt:[j]}],mr:[{mr:[j]}],mb:[{mb:[j]}],ml:[{ml:[j]}],"space-x":[{"space-x":[B]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[B]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",W,t]}],"min-w":[{"min-w":[W,t,"min","max","fit"]}],"max-w":[{"max-w":[W,t,"none","full","min","max","fit","prose",{screen:[vt]},vt]}],h:[{h:[W,t,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[W,t,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[W,t,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[W,t,"auto","min","max","fit"]}],"font-size":[{text:["base",vt,wt]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",ii]}],"font-family":[{font:[On]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",W]}],"line-clamp":[{"line-clamp":["none",rn,ii]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",pt,W]}],"list-image":[{"list-image":["none",W]}],"list-style-type":[{list:["none","disc","decimal",W]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[e]}],"placeholder-opacity":[{"placeholder-opacity":[b]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[e]}],"text-opacity":[{"text-opacity":[b]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...O(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",pt,wt]}],"underline-offset":[{"underline-offset":["auto",pt,W]}],"text-decoration-color":[{decoration:[e]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:P()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",W]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",W]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[b]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...E(),Ym]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",Xm]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},ef]}],"bg-color":[{bg:[e]}],"gradient-from-pos":[{from:[y]}],"gradient-via-pos":[{via:[y]}],"gradient-to-pos":[{to:[y]}],"gradient-from":[{from:[p]}],"gradient-via":[{via:[p]}],"gradient-to":[{to:[p]}],rounded:[{rounded:[a]}],"rounded-s":[{"rounded-s":[a]}],"rounded-e":[{"rounded-e":[a]}],"rounded-t":[{"rounded-t":[a]}],"rounded-r":[{"rounded-r":[a]}],"rounded-b":[{"rounded-b":[a]}],"rounded-l":[{"rounded-l":[a]}],"rounded-ss":[{"rounded-ss":[a]}],"rounded-se":[{"rounded-se":[a]}],"rounded-ee":[{"rounded-ee":[a]}],"rounded-es":[{"rounded-es":[a]}],"rounded-tl":[{"rounded-tl":[a]}],"rounded-tr":[{"rounded-tr":[a]}],"rounded-br":[{"rounded-br":[a]}],"rounded-bl":[{"rounded-bl":[a]}],"border-w":[{border:[l]}],"border-w-x":[{"border-x":[l]}],"border-w-y":[{"border-y":[l]}],"border-w-s":[{"border-s":[l]}],"border-w-e":[{"border-e":[l]}],"border-w-t":[{"border-t":[l]}],"border-w-r":[{"border-r":[l]}],"border-w-b":[{"border-b":[l]}],"border-w-l":[{"border-l":[l]}],"border-opacity":[{"border-opacity":[b]}],"border-style":[{border:[...O(),"hidden"]}],"divide-x":[{"divide-x":[l]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[l]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[b]}],"divide-style":[{divide:O()}],"border-color":[{border:[s]}],"border-color-x":[{"border-x":[s]}],"border-color-y":[{"border-y":[s]}],"border-color-s":[{"border-s":[s]}],"border-color-e":[{"border-e":[s]}],"border-color-t":[{"border-t":[s]}],"border-color-r":[{"border-r":[s]}],"border-color-b":[{"border-b":[s]}],"border-color-l":[{"border-l":[s]}],"divide-color":[{divide:[s]}],"outline-style":[{outline:["",...O()]}],"outline-offset":[{"outline-offset":[pt,W]}],"outline-w":[{outline:[pt,wt]}],"outline-color":[{outline:[e]}],"ring-w":[{ring:G()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[e]}],"ring-opacity":[{"ring-opacity":[b]}],"ring-offset-w":[{"ring-offset":[pt,wt]}],"ring-offset-color":[{"ring-offset":[e]}],shadow:[{shadow:["","inner","none",vt,tf]}],"shadow-color":[{shadow:[On]}],opacity:[{opacity:[b]}],"mix-blend":[{"mix-blend":[...Q(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":Q()}],filter:[{filter:["","none"]}],blur:[{blur:[n]}],brightness:[{brightness:[r]}],contrast:[{contrast:[u]}],"drop-shadow":[{"drop-shadow":["","none",vt,W]}],grayscale:[{grayscale:[c]}],"hue-rotate":[{"hue-rotate":[d]}],invert:[{invert:[h]}],saturate:[{saturate:[_]}],sepia:[{sepia:[q]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[n]}],"backdrop-brightness":[{"backdrop-brightness":[r]}],"backdrop-contrast":[{"backdrop-contrast":[u]}],"backdrop-grayscale":[{"backdrop-grayscale":[c]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[d]}],"backdrop-invert":[{"backdrop-invert":[h]}],"backdrop-opacity":[{"backdrop-opacity":[b]}],"backdrop-saturate":[{"backdrop-saturate":[_]}],"backdrop-sepia":[{"backdrop-sepia":[q]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[o]}],"border-spacing-x":[{"border-spacing-x":[o]}],"border-spacing-y":[{"border-spacing-y":[o]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",W]}],duration:[{duration:ue()}],ease:[{ease:["linear","in","out","in-out",W]}],delay:[{delay:ue()}],animate:[{animate:["none","spin","ping","pulse","bounce",W]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[N]}],"scale-x":[{"scale-x":[N]}],"scale-y":[{"scale-y":[N]}],rotate:[{rotate:[Mn,W]}],"translate-x":[{"translate-x":[M]}],"translate-y":[{"translate-y":[M]}],"skew-x":[{"skew-x":[k]}],"skew-y":[{"skew-y":[k]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",W]}],accent:[{accent:["auto",e]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",W]}],"caret-color":[{caret:[e]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":P()}],"scroll-mx":[{"scroll-mx":P()}],"scroll-my":[{"scroll-my":P()}],"scroll-ms":[{"scroll-ms":P()}],"scroll-me":[{"scroll-me":P()}],"scroll-mt":[{"scroll-mt":P()}],"scroll-mr":[{"scroll-mr":P()}],"scroll-mb":[{"scroll-mb":P()}],"scroll-ml":[{"scroll-ml":P()}],"scroll-p":[{"scroll-p":P()}],"scroll-px":[{"scroll-px":P()}],"scroll-py":[{"scroll-py":P()}],"scroll-ps":[{"scroll-ps":P()}],"scroll-pe":[{"scroll-pe":P()}],"scroll-pt":[{"scroll-pt":P()}],"scroll-pr":[{"scroll-pr":P()}],"scroll-pb":[{"scroll-pb":P()}],"scroll-pl":[{"scroll-pl":P()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",W]}],fill:[{fill:[e,"none"]}],"stroke-w":[{stroke:[pt,wt,ii]}],stroke:[{stroke:[e,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},of=Bm(af),Mi={status:"",repo:"",thread:"",action:"",intent:"",actor:""},lf=new qu({defaultOptions:{queries:{retry:1}}}),to=12,uf=12,cf=10080*60*1e3,df=1e3,Al=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC";function V(...e){return of(au(e))}async function ee(e,t){const n=new Headers(t==null?void 0:t.headers);n.set("Accept","application/json");const r=await fetch(e,{...t,headers:n});if(!r.ok)throw new Error(`${r.status} ${r.statusText}`);return r.json()}function Qe(e){if(e==null)return"n/a";const t=Math.max(0,Math.floor(e));if(t<60)return`${t}s`;const n=Math.floor(t/60);return n<60?`${n}m ${t%60}s`:`${Math.floor(n/60)}h ${n%60}m`}const hf=new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"short"}),pf=new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"});function hr(e){if(!e)return null;const t=new Date(e);return Number.isNaN(t.getTime())?null:t}function mf(e){const t=hr(e);return t?hf.format(t):e??""}function Hn(e){const t=hr(e);return t?pf.format(t):e??""}function Ll(e,t){const n=hr(e);if(!n)return e??"";const r=t-n.getTime(),s=Math.abs(r);if(s>cf)return Hn(e);const a=r>=0?"ago":"from now",o=Math.round(s/1e3);if(o<45)return r>=0?"just now":"soon";if(o<90)return`1m ${a}`;const l=Math.round(o/60);if(l<60)return`${l}m ${a}`;if(l<90)return`1h ${a}`;const u=Math.round(l/60);return u<24?`${u}h ${a}`:u<36?`1d ${a}`:`${Math.round(u/24)}d ${a}`}function Ie({value:e,compact:t=!1,relative:n=!1,now:r=Date.now()}){const s=hr(e);return s?i.jsx("time",{dateTime:s.toISOString(),title:`UTC: ${s.toISOString()}`,children:n?Ll(e,r):t?Hn(e):mf(e)}):i.jsx(i.Fragment,{children:e??""})}function Ml(e,t){const n=hr(e);return n?Math.max(0,Math.floor((t-n.getTime())/1e3)):null}function as(e,t){return e.status==="running"?Ml(e.started_at,t)??e.runtime_seconds:e.runtime_seconds}function os(e,t){return e.status==="pending"?Ml(e.created_at,t)??e.queue_wait_seconds:e.queue_wait_seconds}function ff(e){const[t,n]=T.useState(()=>Date.now());return T.useEffect(()=>{if(!e)return;n(Date.now());const r=window.setInterval(()=>n(Date.now()),df);return()=>window.clearInterval(r)},[e]),t}function xf(e){return(e??"").split(/\r?\n/).map(n=>n.trim()).find(Boolean)??""}function Mr(e,t,n=1){const r=xf(t),s=n>1?` (${n})`:"";return r?`${e}${s}: ${r}`:`${e}${s}`}function Or(e){return e==="openclaw_stdout"||e==="openclaw_stderr"}function Ol(e){return e.map(t=>t==null?void 0:t.trim()).filter(Boolean).join(` -`)}function gf(e){const t=[];for(const n of e){const r=t[t.length-1];if(r&&Or(n.event_type)&&r.eventType===n.event_type){r.count+=1,r.meta=n.ts,r.detail=Ol([r.detail,n.detail]),r.summary=Mr(n.summary,r.detail,r.count);continue}t.push({id:String(n.id),badge:n.event_type,meta:n.ts,summary:Or(n.event_type)?Mr(n.summary,n.detail):n.summary,detail:n.detail,eventType:n.event_type,count:1})}return t}function bf(e){const t=[];return e.forEach((n,r)=>{const s=t[t.length-1];if(s&&Or(n.kind)&&s.kind===n.kind){s.count+=1,s.meta=n.timestamp,s.text=Ol([s.text,n.text]),s.summary=Mr(`${n.role} · ${n.kind}`,s.text,s.count);return}t.push({id:`${n.timestamp??"entry"}-${r}`,badge:n.title,meta:n.timestamp,summary:Or(n.kind)?Mr(`${n.role} · ${n.kind}`,n.text):`${n.role} · ${n.kind}`,text:n.text,kind:n.kind,count:1})}),t}function no(e,t,n,r){return e==="openclaw_stdout"?!1:t||n>=r-2}function yf(e){return{pending:{badge:"border-amber-300 bg-amber-50 text-amber-800",dot:"bg-amber-500"},running:{badge:"border-blue-300 bg-blue-50 text-blue-700",dot:"bg-blue-600"},blocked:{badge:"border-red-300 bg-red-50 text-red-700",dot:"bg-red-600"},denied:{badge:"border-red-300 bg-red-50 text-red-700",dot:"bg-red-600"},done:{badge:"border-emerald-300 bg-emerald-50 text-emerald-700",dot:"bg-emerald-600"},waiting_approval:{badge:"border-slate-300 bg-slate-50 text-slate-700",dot:"bg-slate-500"}}[e]??{badge:"border-slate-300 bg-slate-50 text-slate-700",dot:"bg-slate-500"}}function wf(e,t){const n=new URLSearchParams;for(const[r,s]of Object.entries(e))s.trim()&&n.set(r,s.trim());return n.set("limit",String(t)),`/api/jobs?${n.toString()}`}function vf(e,t,n=50){const r=new URLSearchParams;return e.trim()&&r.set("repo",e.trim()),t.trim()&&r.set("status",t.trim()),r.set("limit",String(n)),`/api/knowledge?${r.toString()}`}function jf(e){return{timeseries:e==="overview",hooks:e==="hooks",deliveries:e==="deliveries"}}function kf(e,t,n="day"){return`/api/webhooks/github/timeseries?${new URLSearchParams({from:e,to:t,bucket:n}).toString()}`}function Nf(e=50,t){const n=new URLSearchParams({limit:String(e)});return t&&n.set("cursor",t),`/api/webhooks/github/hooks?${n.toString()}`}function Sf(e=50,t,n){const r=new URLSearchParams({limit:String(e)});t&&r.set("cursor",t);for(const[s,a]of Object.entries(n??{}))a!=null&&a.trim()&&r.set(s,a.trim());return`/api/webhooks/github/deliveries?${r.toString()}`}function Sr(e=new Date){return{from:new Date(e.getTime()-720*60*60*1e3).toISOString(),to:e.toISOString()}}function Cf(e=Al){return`/api/metrics/summary?timezone=${encodeURIComponent(e)}`}function Ze(e){try{const t=new URL(e);return t.protocol==="https:"||t.protocol==="http:"?t.href:"#"}catch{return"#"}}function Rr(){return"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}function _f(e){return!!(e&&typeof e=="object"&&"type"in e&&e.type==="github-agent-bridge:push")}function Ef(e){const t="=".repeat((4-e.length%4)%4),n=(e+t).replace(/-/g,"+").replace(/_/g,"/"),r=window.atob(n),s=new Uint8Array(r.length);for(let a=0;an.id===t.id)?e:[...e,t]}function Rf(e,t){const n=ro(t);return e.some(r=>ro(r)===n)?e:[...e,t]}function ro(e){return`${e.timestamp??""}:${e.role}:${e.kind}:${e.title}:${e.text}`}function If(e){return["claimed","dispatch_started","dispatch_finished","done","blocked","denied","waiting_approval"].includes(e)}function zn(e){return["blocked","denied","waiting_approval"].includes(e)}function Oi(e,t){return e.status!=="running"?!1:t!=null&&t.is_admin?!0:!!(t!=null&&t.login&&e.trigger_actor&&t.login.toLowerCase()===e.trigger_actor.toLowerCase())}function Tf(e=window.location.pathname){const t=e.match(/^\/jobs\/(\d+)\/?$/);return t?Number(t[1]):null}function Af(e=window.location.pathname){return/^\/knowledge\/?$/.test(e)}function Lf(e=window.location.pathname){return/^\/mcp\/?$/.test(e)}function Mf(e=window.location.pathname){return/^\/system\/?$/.test(e)}function Of(e=window.location.pathname){const t=e.match(/^\/webhooks\/hooks\/([^/]+)\/?$/);return t?decodeURIComponent(t[1]):null}function si(e=window.location.pathname){return/^\/webhooks(?:\/hooks\/[^/]+)?\/?$/.test(e)}function Dl(e){return e.startsWith("repo:")?e.slice(5):e}function io(e){return Object.values(e).some(t=>t.trim()!=="")}function Df(e){return[{key:"status",label:"Status",value:e.status},{key:"repo",label:"Repo",value:e.repo},{key:"thread",label:"Thread",value:e.thread},{key:"action",label:"Action",value:e.action},{key:"actor",label:"Actor",value:e.actor.trim()?`@${e.actor.trim().replace(/^@/,"")}`:""},{key:"intent",label:"Intent",value:e.intent}].filter(t=>t.value.trim()!=="")}function Ff(){var cs,ds,hs,ps,ms,fs,xs,gs,bs,ys,ws,vs,js,ks,Ns,Ss,Cs,_s,Es,Ps,Rs,Is,Ts,As,Ls,Ms,Os,Ds,Fs,zs,qs,Bs,Us,$s,Hs,Ks,Qs,Vs,Ws,Gs,Js,Xs,Ys;const e=Do(),[t,n]=T.useState(Mi),[r,s]=T.useState(to),a=T.useRef(!1),[o,l]=T.useState(""),[u,c]=T.useState("proposed"),[d,h]=T.useState("overview"),[m,p]=T.useState({hook_id:"",event_name:"",repository:"",result:""}),[y,w]=T.useState(()=>Sr()),[j,b]=T.useState(null),[S,_]=T.useState(""),[N,q]=T.useState(()=>window.location.pathname),[k,B]=T.useState(null),M=Tf(N),v=M!==null,F=Af(N),L=Lf(N),P=Mf(N),G=si(N),z=Of(N),E=!v&&!F&&!L&&!P&&!G,O=M,Q=ge({queryKey:["metrics",Al],queryFn:()=>ee(Cf()),enabled:E||P}),he=ge({queryKey:["dashboard-status"],queryFn:()=>ee("/api/status")}),se=ge({queryKey:["me"],queryFn:()=>ee("/api/me"),refetchInterval:!1}),f=G&&!!((ds=(cs=se.data)==null?void 0:cs.user)!=null&&ds.is_admin&&((hs=he.data)!=null&&hs.webhook_configured)),ue=jf(d),Se=ge({queryKey:["web-push-config"],queryFn:()=>ee("/api/web-push/config"),enabled:!!((ps=se.data)!=null&&ps.user)}),x=ge({queryKey:["about"],queryFn:()=>ee("/api/about")}),De=ge({queryKey:["job-actors"],queryFn:()=>ee("/api/jobs/actors"),enabled:E}),we=ge({queryKey:["jobs",t,r],queryFn:()=>ee(wf(t,r)),enabled:E,placeholderData:A=>A}),me=ge({queryKey:["processes"],queryFn:()=>ee("/api/processes"),enabled:P}),et=ge({queryKey:["systemd"],queryFn:()=>ee("/api/systemd"),enabled:P}),Fe=ge({queryKey:["alerts"],queryFn:()=>ee("/api/alerts"),enabled:P}),Ve=ge({queryKey:["webhook-summary"],queryFn:()=>ee("/api/webhooks/github/summary"),enabled:f}),tt=ge({queryKey:["webhook-timeseries",y.from,y.to,"day"],queryFn:()=>ee(kf(y.from,y.to)),enabled:f&&ue.timeseries}),At=ge({queryKey:["webhook-exceptions"],queryFn:()=>ee("/api/webhooks/github/exceptions"),enabled:f&&ue.timeseries}),ct=pa({queryKey:["webhook-hooks"],queryFn:({pageParam:A})=>ee(Nf(50,A)),initialPageParam:null,getNextPageParam:A=>A.next_cursor??void 0,enabled:f&&ue.hooks&&z===null}),dt=pa({queryKey:["webhook-deliveries",m],queryFn:({pageParam:A})=>ee(Sf(50,A,m)),initialPageParam:null,getNextPageParam:A=>A.next_cursor??void 0,enabled:f&&ue.deliveries&&z===null}),Yt=ge({queryKey:["webhook-hook",z],queryFn:()=>ee(`/api/webhooks/github/hooks/${encodeURIComponent(z??"")}`),enabled:f&&z!==null}),Lt=ge({queryKey:["knowledge",o,u],queryFn:()=>ee(vf(o,u)),enabled:F}),Mt=ge({queryKey:["mcp-tokens"],queryFn:()=>ee("/api/mcp/tokens"),enabled:L&&!!((ms=se.data)!=null&&ms.user)}),pr=ge({queryKey:["mcp-users"],queryFn:()=>ee("/api/mcp/users"),enabled:L&&!!((fs=se.data)!=null&&fs.user)}),Zt=ge({queryKey:["job",O],queryFn:()=>ee(`/api/jobs/${O}`),enabled:O!==null}),_n=ge({queryKey:["job-session",O],queryFn:()=>ee(`/api/jobs/${O}/session`),enabled:O!==null}),En=ge({queryKey:["job-session-events",O],queryFn:()=>ee(`/api/jobs/${O}/session/events`),enabled:O!==null}),mr=ge({queryKey:["job-session-transcript",O],queryFn:()=>ee(`/api/jobs/${O}/session/transcript`),enabled:O!==null}),fr=T.useCallback(async A=>{const ae=await ee(`/api/jobs/${A}/retry`,{method:"POST"});e.setQueryData(["job",A],{job:ae.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]})},[e]),xr=T.useCallback(async A=>{const ae=await ee(`/api/jobs/${A}/dismiss`,{method:"POST"});e.setQueryData(["job",A],{job:ae.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]})},[e]),gr=T.useCallback(async(A,ae)=>{const pe=await ee(`/api/jobs/${A}/cancel`,{method:"POST",body:JSON.stringify({reason:ae||""})});e.setQueryData(["job",A],{job:pe.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]}),e.invalidateQueries({queryKey:["dashboard-status"]})},[e]),br=T.useCallback(async(A,ae)=>{await ee(`/api/knowledge/proposals/${encodeURIComponent(A)}/${ae}`,{method:"POST"}),e.invalidateQueries({queryKey:["knowledge"]}),e.invalidateQueries({queryKey:["dashboard-status"]})},[e]),C=T.useCallback(async A=>{await ee(`/api/knowledge/rules/${encodeURIComponent(A)}`,{method:"DELETE"}),e.invalidateQueries({queryKey:["knowledge"]})},[e]),I=T.useCallback(async(A,ae)=>{await ee(`/api/knowledge/rules/${encodeURIComponent(A)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({scope:ae})}),e.invalidateQueries({queryKey:["knowledge"]})},[e]),H=T.useCallback(async(A,ae)=>{const pe=await ee("/api/mcp/tokens",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:A,user_login:ae||void 0})});return e.invalidateQueries({queryKey:["mcp-tokens"]}),pe},[e]),X=T.useCallback(async(A,ae)=>{await ee(`/api/mcp/tokens/${encodeURIComponent(A)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({user_login:ae})}),e.invalidateQueries({queryKey:["mcp-tokens"]}),e.invalidateQueries({queryKey:["mcp-users"]})},[e]),ie=T.useCallback(async A=>{await ee(`/api/mcp/tokens/${encodeURIComponent(A)}`,{method:"DELETE"}),e.invalidateQueries({queryKey:["mcp-tokens"]})},[e]),Pe=T.useCallback(async A=>{const ae={refresh:"/api/autoupdate/refresh",apply:"/api/autoupdate/apply",complete:"/api/autoupdate/complete-pending"}[A];b(A),_("");try{await ee(ae,{method:"POST"}),e.invalidateQueries({queryKey:["dashboard-status"]})}catch(pe){e.invalidateQueries({queryKey:["dashboard-status"]}),_(pe instanceof Error?pe.message:String(pe))}finally{b(null)}},[e]),ht=T.useCallback(async()=>{var Zs;const A=(Zs=Se.data)==null?void 0:Zs.public_key;if(!A)throw new Error("web_push_not_configured");if(!Rr())throw new Error("web_push_not_supported");if(await window.Notification.requestPermission()!=="granted")throw new Error("notification_permission_denied");const pe=await navigator.serviceWorker.register("/service-worker.js"),ru=await pe.pushManager.getSubscription()??await pe.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Ef(A)});await ee("/api/web-push/subscriptions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(ru.toJSON())}),e.invalidateQueries({queryKey:["web-push-config"]})},[e,(xs=Se.data)==null?void 0:xs.public_key]),We=T.useCallback(async()=>{if(!Rr())return;const ae=await(await navigator.serviceWorker.ready).pushManager.getSubscription();if(!ae)return;const pe=ae.endpoint;await ae.unsubscribe(),await ee("/api/web-push/subscriptions",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({endpoint:pe})}),e.invalidateQueries({queryKey:["web-push-config"]})},[e]);T.useEffect(()=>{var A;!((A=Se.data)!=null&&A.status.enabled)||!Rr()||navigator.serviceWorker.register("/service-worker.js").catch(()=>{})},[(gs=Se.data)==null?void 0:gs.status.enabled]),T.useEffect(()=>{if(O===null)return;const A=new EventSource(`/api/jobs/${O}/session/stream`);return A.addEventListener("session_event",ae=>{const pe=Dr(ae);pe&&(e.setQueryData(["job-session-events",O],bt=>({events:Pf((bt==null?void 0:bt.events)??[],pe)})),If(pe.event_type)&&(e.invalidateQueries({queryKey:["job",O]}),e.invalidateQueries({queryKey:["jobs"]})))}),A.addEventListener("transcript_entry",ae=>{const pe=Dr(ae);!pe||pe.job_id!==O||e.setQueryData(["job-session-transcript",O],bt=>({entries:Rf((bt==null?void 0:bt.entries)??[],pe.entry)}))}),A.onerror=()=>{e.invalidateQueries({queryKey:["job",O]}),e.invalidateQueries({queryKey:["job-session-events",O]}),e.invalidateQueries({queryKey:["job-session-transcript",O]})},()=>A.close()},[O,e]),T.useEffect(()=>{const A=()=>{si(window.location.pathname)&&w(Sr()),q(window.location.pathname)};return window.addEventListener("popstate",A),()=>window.removeEventListener("popstate",A)},[]),T.useEffect(()=>{if(!("serviceWorker"in navigator))return;const A=ae=>{if(!_f(ae.data))return;const pe={...ae.data.payload,id:Date.now(),receivedAt:Date.now()};B(pe),pe.job_id&&(e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["job",pe.job_id]}),e.invalidateQueries({queryKey:["metrics"]}))};return navigator.serviceWorker.addEventListener("message",A),()=>navigator.serviceWorker.removeEventListener("message",A)},[e]),T.useEffect(()=>{if(!k)return;const A=window.setTimeout(()=>B(null),12e3);return()=>window.clearTimeout(A)},[k]);const Ot=T.useCallback(A=>{window.history.pushState({},"",Sn(A)),q(window.location.pathname)},[]),$e=T.useCallback(A=>{window.history.pushState({},"",A),si(A)&&w(Sr()),q(window.location.pathname)},[]),be=((bs=Q.data)==null?void 0:bs.metrics.status_counts)??{},Ge=((ys=we.data)==null?void 0:ys.jobs)??[],Je=T.useCallback(A=>{n(A),s(to),a.current=!1},[]);T.useEffect(()=>{we.isFetching||(a.current=!1)},[we.isFetching]);const Gl=T.useCallback(()=>{a.current||(a.current=!0,s(A=>A+uf))},[]),gt=O?((ws=Zt.data)==null?void 0:ws.job)??null:null,Jl=Ge.some(A=>A.status==="running"||A.status==="pending")||(gt==null?void 0:gt.status)==="running"||(gt==null?void 0:gt.status)==="pending"||!!((vs=me.data)!=null&&vs.running_jobs.length),Pn=ff(Jl),Xl=i.jsx(Yf,{selectedJobId:O,selectedJob:gt,loading:Zt.isLoading,error:Zt.error,session:(js=_n.data)==null?void 0:js.session,sessionEvents:(ks=En.data)==null?void 0:ks.events,transcript:(Ns=mr.data)==null?void 0:Ns.entries,now:Pn}),Yl=((Ss=ct.data)==null?void 0:Ss.pages.flatMap(A=>A.hooks))??[],Zl=((Cs=dt.data)==null?void 0:Cs.pages.flatMap(A=>A.deliveries))??[],eu=d==="overview"?tt.isLoading:d==="hooks"?ct.isLoading:dt.isLoading,tu=d==="overview"?tt.error:d==="hooks"?ct.error:dt.error,nu=()=>{Ve.refetch(),d==="overview"&&At.refetch(),d==="overview"&&w(Sr()),d==="hooks"&&ct.refetch(),d==="deliveries"&&dt.refetch()};return i.jsxs("div",{className:"min-h-screen bg-background text-foreground",children:[i.jsx("header",{className:"border-b border-slate-800 bg-slate-950 text-white",children:i.jsxs("div",{className:"mx-auto flex w-full max-w-[1440px] items-center justify-between gap-3 px-4 py-4 md:px-6",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsx("h1",{className:"truncate text-xl font-semibold",children:"GitHub Agent Bridge"}),i.jsx(zf,{about:x.data})]}),i.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[i.jsx(cx,{config:Se.data,loading:Se.isLoading,onEnable:ht,onDisable:We}),i.jsx(ux,{user:(_s=se.data)==null?void 0:_s.user,loading:se.isLoading})]})]})}),i.jsxs("main",{className:"mx-auto grid w-full max-w-[1440px] gap-4 px-3 py-4 sm:px-4 md:px-6 md:py-5",children:[i.jsx(Kf,{isDashboardRoute:E,isSystemRoute:P,isKnowledgeRoute:F,isMcpRoute:L,isWebhooksRoute:G,showWebhooks:!!((Ps=(Es=se.data)==null?void 0:Es.user)!=null&&Ps.is_admin&&((Rs=he.data)!=null&&Rs.webhook_configured)),knowledgeBadgeCount:((As=(Ts=(Is=he.data)==null?void 0:Is.metrics)==null?void 0:Ts.knowledge)==null?void 0:As.proposed)??0,onNavigate:$e}),i.jsx(dx,{notification:k,onDismiss:()=>B(null),onNavigate:$e}),M!==null?i.jsx(Xf,{jobId:M,detail:Xl,selectedJob:gt,user:(Ls=se.data)==null?void 0:Ls.user,onBackToDashboard:()=>$e("/"),onRetry:fr,onDismiss:xr,onCancel:gr,onRefresh:()=>{Zt.refetch(),_n.refetch(),En.refetch(),mr.refetch()}}):F?i.jsx(Zf,{data:Lt.data,loading:Lt.isLoading,error:Lt.error,repo:o,status:u,user:(Ms=se.data)==null?void 0:Ms.user,now:Pn,onRepoChange:l,onStatusChange:c,onApprove:A=>br(A,"approve"),onReject:A=>br(A,"reject"),onUpdateRuleScope:I,onDeleteRule:C,onRefresh:()=>Lt.refetch()}):L?i.jsx(sx,{tokens:(Os=Mt.data)==null?void 0:Os.tokens,loading:Mt.isLoading,error:Mt.error,user:(Ds=se.data)==null?void 0:Ds.user,ownerOptions:((Fs=pr.data)==null?void 0:Fs.users)??[],dashboardUrl:(zs=he.data)==null?void 0:zs.dashboard_url,dashboardUrlSource:(qs=he.data)==null?void 0:qs.dashboard_url_source,now:Pn,onCreate:H,onUpdateOwner:X,onRevoke:ie,onRefresh:()=>Mt.refetch()}):G?z?i.jsx(Gf,{data:Yt.data,loading:Yt.isLoading,error:Yt.error,onBack:()=>{h("hooks"),$e("/webhooks")},onRefresh:()=>Yt.refetch(),onViewHook:A=>$e(`/webhooks/hooks/${encodeURIComponent(A)}`)}):i.jsx(Qf,{summary:Ve.data,timeseries:(Bs=tt.data)==null?void 0:Bs.points,exceptions:(Us=At.data)==null?void 0:Us.exceptions,hooks:Yl,deliveries:Zl,section:d,summaryLoading:Ve.isLoading,sectionLoading:eu,loadingMore:d==="hooks"?ct.isFetchingNextPage:dt.isFetchingNextPage,hasMore:d==="hooks"?ct.hasNextPage:dt.hasNextPage,deliveryFilters:m,error:Ve.error??tu,onSectionChange:h,onLoadMore:()=>d==="hooks"?ct.fetchNextPage():dt.fetchNextPage(),onDeliveryFiltersChange:p,onViewHook:A=>$e(`/webhooks/hooks/${encodeURIComponent(A)}`),onRefresh:nu}):P?i.jsx(Jf,{processes:me.data,processesLoading:me.isLoading,processesError:me.error,systemd:et.data,systemdLoading:et.isLoading,systemdError:et.error,alerts:($s=Fe.data)==null?void 0:$s.alerts,alertsLoading:Fe.isLoading,alertsError:Fe.error,now:Pn,onRefreshProcesses:()=>me.refetch(),onRefreshSystemd:()=>et.refetch(),onRefreshAlerts:()=>Fe.refetch()}):i.jsxs(i.Fragment,{children:[Q.error?i.jsx(Ne,{tone:"error",text:Q.error.message}):null,he.error?i.jsx(Ne,{tone:"error",text:he.error.message}):null,i.jsx(qf,{state:(Hs=he.data)==null?void 0:Hs.autoupdate,isAdmin:!!((Qs=(Ks=se.data)==null?void 0:Ks.user)!=null&&Qs.is_admin),runningAction:j,actionError:S,onRefresh:()=>Pe("refresh"),onApply:()=>Pe("apply"),onCompletePending:()=>Pe("complete")}),i.jsxs("section",{className:"grid grid-cols-2 gap-3 xl:grid-cols-4","aria-label":"Summary metrics",children:[i.jsx(_e,{title:"Pending",value:be.pending??0,icon:i.jsx($o,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Running",value:be.running??0,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Blocked",value:be.blocked??0,icon:i.jsx(zr,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Done",value:be.done??0,icon:i.jsx(wn,{className:"h-5 w-5"})})]}),i.jsxs("section",{className:"grid gap-3",children:[i.jsx(hx,{count:Ge.length,limit:r,loading:we.isLoading,onRefresh:()=>we.refetch()}),i.jsxs(fe,{title:"Recent jobs",flushHeader:!0,children:[i.jsx(px,{filters:t,actorOptions:((Vs=De.data)==null?void 0:Vs.actors)??[],onChange:Je}),we.error?i.jsx(Ne,{tone:"error",text:we.error.message}):null,i.jsx(fx,{jobs:Ge,loading:we.isLoading,loadingMore:we.isFetching&&!we.isLoading,hasMore:Ge.length>=r,onLoadMore:Gl,onViewJob:Ot,now:Pn,user:(Ws=se.data)==null?void 0:Ws.user,onRetry:fr,onDismiss:xr,onCancel:gr})]}),i.jsx(fe,{title:"Runtime usage",action:i.jsx(lt,{onClick:()=>Q.refetch()}),children:i.jsx(Ex,{usage:(Gs=Q.data)==null?void 0:Gs.metrics.runtime_usage,loading:Q.isLoading,totalJobs:lo(be)})})]}),i.jsxs("section",{className:"grid gap-4 xl:grid-cols-3",children:[i.jsx(fe,{title:"Runtime percentiles",children:i.jsx(oo,{label:"runtime",values:(Js=Q.data)==null?void 0:Js.metrics.runtime_seconds})}),i.jsx(fe,{title:"Jobs per day",children:i.jsx(_x,{values:(Xs=Q.data)==null?void 0:Xs.metrics.by_created_day,loading:Q.isLoading,totalJobs:lo(be)})}),i.jsx(fe,{title:"Queue wait percentiles",children:i.jsx(oo,{label:"queue wait",values:(Ys=Q.data)==null?void 0:Ys.metrics.queue_wait_seconds})})]})]})]})]})}function zf({about:e}){const t=e!=null&&e.version?`v${e.version}`:"version loading";return i.jsxs("p",{className:"flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-slate-300",children:[i.jsx("span",{children:"Operational dashboard"}),i.jsx("span",{className:"font-mono text-xs text-slate-400",children:t}),e!=null&&e.repository_url?i.jsxs("a",{className:"inline-flex items-center gap-1 text-xs font-semibold text-slate-200 hover:underline",href:Ze(e.repository_url),rel:"noreferrer",target:"_blank",children:[i.jsx(Gt,{className:"h-3.5 w-3.5","aria-hidden":!0}),"GitHub"]}):null]})}function qf({state:e,isAdmin:t,runningAction:n=null,actionError:r="",onRefresh:s,onApply:a,onCompletePending:o}){var j,b,S,_,N,q,k,B,M,v,F;if(!e)return null;const l=(b=(j=e==null?void 0:e.target)==null?void 0:j.tag_name)==null?void 0:b.trim();if(!t||!l||(e==null?void 0:e.decision)==="noop")return null;const u=Bf(e.decision),c=((S=e.queue)==null?void 0:S.active_total)??0,d=Uf((_=e.classification)==null?void 0:_.risk),h=$f((N=e.target)==null?void 0:N.body),m=((k=(q=e.classification)==null?void 0:q.migration_files)==null?void 0:k.length)??0,p=((M=(B=e.classification)==null?void 0:B.risky_files)==null?void 0:M.length)??0,y=!!(e.executor_reload_pending&&e.dashboard_applied_at&&o),w=!!(a&&m===0);return i.jsxs("section",{className:"rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-950 shadow-sm","aria-label":"Update available",children:[i.jsxs("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[i.jsx(zr,{className:"h-4 w-4 text-amber-700","aria-hidden":!0}),i.jsx("h2",{className:"text-sm font-semibold",children:"Update available"}),i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-1.5 py-0.5 font-mono text-[11px] text-amber-800",children:l}),(v=e.target)!=null&&v.url?i.jsxs("a",{className:"inline-flex items-center gap-1 text-xs font-semibold text-amber-800 hover:underline",href:Ze(e.target.url),rel:"noreferrer",target:"_blank",children:[i.jsx(Gt,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Release"]}):null]}),i.jsxs("p",{className:"mt-1 text-sm text-amber-900",children:[u,e.installed_tag?i.jsxs("span",{className:"font-mono",children:[" from ",e.installed_tag]}):null]}),i.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[s?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-amber-300 bg-white px-2.5 text-xs font-semibold text-amber-900 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:s,children:[i.jsx(ur,{className:V("h-3.5 w-3.5",n==="refresh"&&"animate-spin"),"aria-hidden":!0}),n==="refresh"?"Checking...":"Check now"]}):null,w?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md bg-amber-800 px-2.5 text-xs font-semibold text-white hover:bg-amber-900 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:()=>{window.confirm(`Apply ${l}? This can restart bridge services according to the recorded safe plan.`)&&(a==null||a())},children:[i.jsx(wn,{className:"h-3.5 w-3.5","aria-hidden":!0}),n==="apply"?"Applying...":"Apply update"]}):null,y?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-amber-300 bg-white px-2.5 text-xs font-semibold text-amber-900 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:o,children:[i.jsx(Gn,{className:"h-3.5 w-3.5","aria-hidden":!0}),n==="complete"?"Completing...":"Complete reload"]}):null]})]}),i.jsxs("div",{className:"grid gap-2 text-xs sm:grid-cols-3 lg:min-w-[420px]",children:[i.jsx(ai,{label:"Impact",value:d}),i.jsx(ai,{label:"Active jobs",value:String(c)}),i.jsx(ai,{label:"Admin only",value:"autoupdate"})]})]}),e.blocked_reason||e.executor_reload_pending||m>0||p>0?i.jsxs("div",{className:"mt-3 flex flex-wrap gap-2 text-xs",children:[e.executor_reload_pending?i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1 font-semibold",children:"executor reload pending"}):null,e.blocked_reason?i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1 font-mono",children:e.blocked_reason}):null,m>0?i.jsxs("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1",children:[m," migration file",m===1?"":"s"]}):null,p>0?i.jsxs("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1",children:[p," executor/shared file",p===1?"":"s"]}):null]}):null,h?i.jsxs("div",{className:"mt-3 rounded-md border border-amber-200 bg-white/70 p-2.5",children:[i.jsx("div",{className:"text-[11px] font-semibold uppercase text-amber-800",children:"Changelog preview"}),i.jsx(Hf,{markdown:h})]}):null,(F=e.warnings)!=null&&F.length?i.jsx("div",{className:"mt-2 font-mono text-xs text-amber-800",children:e.warnings[0]}):null,r?i.jsxs("div",{className:"mt-2 rounded-sm border border-amber-300 bg-white px-2 py-1 font-mono text-xs text-amber-900",children:["Action failed: ",r]}):null]})}function ai({label:e,value:t}){return i.jsxs("div",{className:"min-w-0 rounded-md border border-amber-200 bg-white/80 px-2 py-1.5",children:[i.jsx("div",{className:"text-[11px] font-semibold uppercase text-amber-700",children:e}),i.jsx("div",{className:"mt-0.5 truncate font-mono text-xs text-amber-950",children:t})]})}function Bf(e){return{stage_dashboard_reload:"Dashboard reload can be staged now",stage_defer_executor_reload:"Dashboard reload can be staged; executor reload waits for the queue",stage_full_reload:"Full reload can be staged now",defer_migration:"Migration release is waiting for a quiet queue"}[e??""]??"Update plan recorded"}function Uf(e){return{dashboard_only:"dashboard only",executor_or_queue:"executor or queue",executor_or_shared:"executor or shared",migration_required:"migration",none:"none"}[e??""]??"unknown"}function $f(e){return(e??"").trim()}function Hf({markdown:e}){return i.jsx("div",{className:"mt-1 text-sm leading-relaxed text-amber-950",children:i.jsx(Nm,{allowedElements:["a","blockquote","code","em","h1","h2","h3","h4","li","ol","p","strong","ul"],components:{a:({href:t,children:n})=>i.jsx("a",{className:"font-semibold text-amber-800 underline underline-offset-2",href:Ze(t??""),rel:"noreferrer",target:"_blank",children:n}),blockquote:({children:t})=>i.jsx("blockquote",{className:"mt-2 border-l-2 border-amber-300 pl-2 text-amber-900",children:t}),code:({children:t})=>i.jsx("code",{className:"rounded-sm bg-amber-100 px-1 py-0.5 font-mono text-[0.85em] text-amber-950",children:t}),h1:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h2:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h3:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h4:({children:t})=>i.jsx("h4",{className:"mt-2 text-xs font-semibold uppercase text-amber-800 first:mt-0",children:t}),li:({children:t})=>i.jsx("li",{className:"break-words pl-0.5 [overflow-wrap:anywhere]",children:t}),ol:({children:t})=>i.jsx("ol",{className:"mt-1 list-decimal space-y-1 pl-5 first:mt-0",children:t}),p:({children:t})=>i.jsx("p",{className:"mt-1 break-words [overflow-wrap:anywhere] first:mt-0",children:t}),strong:({children:t})=>i.jsx("strong",{className:"font-semibold",children:t}),em:({children:t})=>i.jsx("em",{className:"italic",children:t}),ul:({children:t})=>i.jsx("ul",{className:"mt-1 list-disc space-y-1 pl-5 first:mt-0",children:t})},children:e})})}function Kf({isDashboardRoute:e,isSystemRoute:t=!1,isKnowledgeRoute:n,isMcpRoute:r=!1,isWebhooksRoute:s=!1,showWebhooks:a=!1,knowledgeBadgeCount:o=0,onNavigate:l}){return i.jsxs("nav",{className:"flex min-w-0 rounded-lg border border-border bg-panel p-1 shadow-sm","aria-label":"Dashboard sections",children:[i.jsxs(Dn,{href:"/",active:e,onNavigate:l,children:[i.jsx(Qo,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Jobs"})]}),i.jsxs(Dn,{href:"/system",active:t,onNavigate:l,children:[i.jsx(nc,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"System"})]}),a?i.jsxs(Dn,{href:"/webhooks",active:s,onNavigate:l,children:[i.jsx(bn,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Webhooks"})]}):null,i.jsxs(Dn,{href:"/knowledge",active:n,onNavigate:l,children:[i.jsx(Hi,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Knowledge"}),o>0?i.jsx("span",{className:V("inline-flex h-5 min-w-5 items-center justify-center rounded-full border px-1 font-mono text-[11px] leading-none",n?"border-white/40 bg-white/15 text-white":"border-amber-200 bg-amber-100 text-amber-800"),"aria-label":`${o} proposed knowledge ${o===1?"item":"items"}`,children:o}):null]}),i.jsxs(Dn,{href:"/mcp",active:r,onNavigate:l,children:[i.jsx(Tr,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"MCP"})]})]})}function qn({text:e}){return i.jsxs("div",{className:"flex items-center justify-center gap-2 py-10 text-sm text-muted",children:[i.jsx(ur,{className:"h-4 w-4 animate-spin","aria-hidden":!0}),e]})}function Qf({summary:e,timeseries:t,exceptions:n,hooks:r,deliveries:s,section:a,summaryLoading:o,sectionLoading:l,loadingMore:u,hasMore:c,deliveryFilters:d,error:h,onSectionChange:m,onLoadMore:p,onDeliveryFiltersChange:y,onViewHook:w,onRefresh:j}){var _,N,q,k,B,M;const b=Object.values((e==null?void 0:e.receipts)??{}).reduce((v,F)=>v+F,0),S=[{id:"overview",label:"Overview"},{id:"hooks",label:"Hooks",count:(_=e==null?void 0:e.totals)==null?void 0:_.hooks},{id:"deliveries",label:"Deliveries",count:(N=e==null?void 0:e.totals)==null?void 0:N.deliveries}];return i.jsxs("section",{className:"grid gap-4",children:[i.jsx(zl,{icon:i.jsx(bn,{className:"h-5 w-5 text-muted","aria-hidden":!0}),title:"GitHub webhooks",subtitle:(e==null?void 0:e.mode)==="canary"?"Canary ingestion health. Only enabled repositories may create jobs.":"Shadow ingestion health. Deliveries are observed but do not create jobs.",action:i.jsx(lt,{onClick:j})}),h?i.jsx(Ne,{tone:"error",text:h.message}):null,i.jsx("div",{className:"flex max-w-full flex-wrap rounded-md border border-border bg-white p-1",role:"tablist","aria-label":"Webhook dashboard section",children:S.map(v=>i.jsxs("button",{type:"button",role:"tab","aria-label":v.count===void 0?v.label:`${v.label} (${v.count} total)`,"aria-selected":a===v.id,className:V("inline-flex h-8 items-center gap-2 rounded px-3 text-sm font-semibold",a===v.id?"bg-primary text-white":"text-muted hover:bg-slate-50 hover:text-foreground"),onClick:()=>m(v.id),children:[v.label,v.count!==void 0?i.jsx("span",{className:"rounded border border-current/30 px-1 font-mono text-[10px]",children:v.count}):null]},v.id))}),i.jsxs("div",{className:"grid grid-cols-2 gap-3 xl:grid-cols-4","aria-label":"Webhook status",children:[i.jsx(_e,{title:"Receipts",value:b,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Duplicates",value:(e==null?void 0:e.duplicate_deliveries)??0,icon:i.jsx(ur,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Cross-source matches",value:(e==null?void 0:e.cross_source_matches)??0,icon:i.jsx(vn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Mode",value:o?"…":(e==null?void 0:e.mode)??"unknown",icon:i.jsx(Ho,{className:"h-5 w-5"})})]}),a==="overview"?i.jsxs(i.Fragment,{children:[i.jsx(fe,{title:"Delivery activity",children:l?i.jsx(qn,{text:"Loading delivery activity…"}):t!=null&&t.length?i.jsx("div",{className:"h-72","aria-label":"Webhook deliveries over time",children:i.jsx(rr,{width:"100%",height:"100%",children:i.jsxs(Fr,{data:t,children:[i.jsx(ir,{strokeDasharray:"3 3"}),i.jsx(sr,{dataKey:"bucket"}),i.jsx(ar,{allowDecimals:!1}),i.jsx(or,{}),i.jsx(ko,{}),i.jsx(Vt,{dataKey:"observed",stackId:"deliveries",fill:"#2563eb"}),i.jsx(Vt,{dataKey:"duplicate",stackId:"deliveries",fill:"#f59e0b"}),i.jsx(Vt,{dataKey:"unsupported",stackId:"deliveries",fill:"#94a3b8"})]})})}):i.jsx(Z,{text:"No webhook activity in the selected 30-day window."})}),i.jsx(fe,{title:"Receipt states",children:o?i.jsx(qn,{text:"Loading webhook summary…"}):Object.keys((e==null?void 0:e.receipts)??{}).length?i.jsx("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:Object.entries((e==null?void 0:e.receipts)??{}).sort(([v],[F])=>v.localeCompare(F)).map(([v,F])=>i.jsx(J,{label:v,value:F},v))}):i.jsx(Z,{text:"No webhook deliveries observed yet."})}),i.jsx(fe,{title:"Cross-source coverage",children:i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-4",children:[i.jsx(J,{label:"Both sources",value:((q=e==null?void 0:e.coverage)==null?void 0:q.both)??0}),i.jsx(J,{label:"IMAP only",value:((k=e==null?void 0:e.coverage)==null?void 0:k.imap_only)??0}),i.jsx(J,{label:"Webhook only",value:((B=e==null?void 0:e.coverage)==null?void 0:B.webhook_only)??0}),i.jsx(J,{label:"Coverage",value:((M=e==null?void 0:e.coverage)==null?void 0:M.ratio)==null?"not measurable":`${Math.round(e.coverage.ratio*100)}%`})]})}),i.jsx(fe,{title:"Exceptions requiring review",children:n!=null&&n.length?i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full min-w-[720px] text-left text-sm",children:[i.jsx("thead",{className:"border-b border-border text-xs text-muted",children:i.jsxs("tr",{children:[i.jsx("th",{className:"px-3 py-2",children:"Type"}),i.jsx("th",{className:"px-3 py-2",children:"Repository"}),i.jsx("th",{className:"px-3 py-2",children:"Reference"}),i.jsx("th",{className:"px-3 py-2",children:"Observed"})]})}),i.jsx("tbody",{children:n.map(v=>i.jsxs("tr",{className:"border-b border-border/70 last:border-0",children:[i.jsx("td",{className:"px-3 py-2 font-semibold",children:v.kind}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs",children:v.repository??"unknown"}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs",children:v.event_key??v.reference}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs text-muted",children:v.created_at})]},`${v.kind}:${v.reference}`))})]})}):i.jsx(Z,{text:"No cross-source exceptions in retained data."})})]}):null,a==="hooks"?i.jsx(fe,{title:"Hook inventory",children:l?i.jsx(qn,{text:"Loading hook inventory…"}):r!=null&&r.length?i.jsx(Di,{noun:"hooks",hasMore:c,loading:u,onLoadMore:p,children:i.jsxs("table",{className:"w-full min-w-[920px] text-left text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"sticky top-0 z-10 border-b border-border bg-panel text-left text-xs text-muted",children:[i.jsx("th",{className:"px-3 py-2",children:"Target"}),i.jsx("th",{className:"px-3 py-2",children:"State"}),i.jsx("th",{className:"px-3 py-2",children:"Configuration"}),i.jsx("th",{className:"px-3 py-2",children:"Last delivery"}),i.jsx("th",{className:"px-3 py-2",children:"Last ping"})]})}),i.jsx("tbody",{children:r.map(v=>i.jsxs("tr",{className:"cursor-pointer border-b border-border/70 last:border-0 hover:bg-slate-50",onClick:()=>w(v.id),children:[i.jsxs("td",{className:"px-3 py-3",children:[i.jsx("button",{type:"button",className:"text-left font-semibold text-primary hover:underline",onClick:F=>{F.stopPropagation(),w(v.id)},children:v.target}),i.jsxs("div",{className:"font-mono text-xs text-muted",children:[v.target_type," · #",v.id]})]}),i.jsx("td",{className:"px-3 py-3",children:i.jsx("span",{className:V("rounded border px-2 py-1 text-xs font-semibold",v.status==="receiving"?"border-emerald-200 bg-emerald-50 text-emerald-700":v.status==="inactive"?"border-red-200 bg-red-50 text-red-700":"border-slate-200 bg-slate-50 text-slate-600"),children:v.status})}),i.jsxs("td",{className:"max-w-sm px-3 py-3 text-xs",children:[i.jsx("div",{children:v.events.join(", ")||"No event snapshot"}),i.jsxs("div",{className:"mt-1 font-mono text-muted",children:[v.content_type??"content type unknown"," · SSL ",v.ssl_verify===null||v.ssl_verify===void 0?"unknown":v.ssl_verify?"verified":"disabled"]})]}),i.jsxs("td",{className:"px-3 py-3 text-xs",children:[i.jsxs("div",{className:"font-semibold",children:[v.last_event_name??"Never",v.last_action?` · ${v.last_action}`:""]}),i.jsx("div",{className:"mt-1 font-mono text-muted",children:v.last_repository??v.last_event_at??"No delivery observed"})]}),i.jsx("td",{className:"px-3 py-3 font-mono text-xs text-muted",children:v.last_ping_at??"Never"})]},v.id))})]})}):i.jsx(Z,{text:"No hook inventory is available. Redeliver a signed ping from GitHub to create the sanitized configuration snapshot."})}):null,a==="deliveries"?i.jsxs(fe,{title:"Recent deliveries",children:[i.jsx(Vf,{filters:d,onChange:y}),l?i.jsx(qn,{text:"Loading deliveries…"}):s!=null&&s.length?i.jsx(Di,{noun:"deliveries",hasMore:c,loading:u,onLoadMore:p,children:i.jsx(Fl,{deliveries:s,onViewHook:w})}):i.jsx(Z,{text:"No deliveries match the current filters."})]}):null]})}function Vf({filters:e,onChange:t}){const n=[{key:"hook_id",label:"Hook ID",placeholder:"690954530"},{key:"event_name",label:"Event",placeholder:"issue_comment"},{key:"repository",label:"Repository",placeholder:"gisce/repository"},{key:"result",label:"Result",placeholder:"observed"}];return i.jsx("div",{className:"grid gap-2 border-b border-border p-3 sm:grid-cols-2 xl:grid-cols-4",children:n.map(r=>i.jsxs("label",{className:"grid gap-1 text-xs font-semibold text-muted",children:[r.label,i.jsx("input",{className:"h-9 rounded-md border border-border bg-white px-2 font-mono text-xs text-foreground",value:e[r.key],placeholder:r.placeholder,onChange:s=>t({...e,[r.key]:s.target.value})})]},r.key))})}function Fl({deliveries:e,onViewHook:t}){return i.jsxs("table",{className:"w-full min-w-[980px] text-left text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"sticky top-0 z-10 border-b border-border bg-panel text-left text-xs text-muted",children:[i.jsx("th",{className:"px-3 py-2",children:"Received"}),i.jsx("th",{className:"px-3 py-2",children:"Hook"}),i.jsx("th",{className:"px-3 py-2",children:"Event"}),i.jsx("th",{className:"px-3 py-2",children:"Repository"}),i.jsx("th",{className:"px-3 py-2",children:"Result"}),i.jsx("th",{className:"px-3 py-2",children:"Delivery"})]})}),i.jsx("tbody",{children:e.map(n=>{var r;return i.jsxs("tr",{className:"border-b border-border/70 last:border-0",children:[i.jsx("td",{className:"px-3 py-3 font-mono text-xs text-muted",children:n.created_at}),i.jsx("td",{className:"px-3 py-3",children:n.hook_id?i.jsxs("button",{type:"button",className:"text-left text-primary hover:underline",onClick:()=>t(n.hook_id),children:[i.jsx("span",{className:"block font-semibold",children:((r=n.hook)==null?void 0:r.target)??`Hook #${n.hook_id}`}),i.jsxs("span",{className:"font-mono text-xs",children:["#",n.hook_id]})]}):i.jsx("span",{className:"text-xs text-muted",children:"Unknown (legacy)"})}),i.jsxs("td",{className:"px-3 py-3 font-semibold",children:[n.event_name,n.action?` · ${n.action}`:""]}),i.jsx("td",{className:"px-3 py-3",children:n.repository??"—"}),i.jsxs("td",{className:"px-3 py-3",children:[i.jsx("span",{className:"rounded border border-border bg-slate-50 px-2 py-1 text-xs font-semibold",children:n.status}),n.duplicate_count?i.jsxs("span",{className:"ml-2 font-mono text-xs text-muted",children:[n.duplicate_count," retries"]}):null]}),i.jsx("td",{className:"max-w-[14rem] truncate px-3 py-3 font-mono text-xs text-muted",title:n.delivery_id,children:n.delivery_id})]},n.delivery_id)})})]})}function Di({noun:e,hasMore:t,loading:n,onLoadMore:r,children:s,className:a}){return i.jsxs("div",{"data-testid":`lazy-scroll-${e}`,className:V("max-h-[640px] overflow-auto rounded-md border border-border",a),children:[s,i.jsx(Wf,{noun:e,hasMore:t,loading:n,onLoadMore:r})]})}function Wf({noun:e,hasMore:t,loading:n,onLoadMore:r}){const s=T.useRef(null),a=T.useRef(!1);return T.useEffect(()=>{n||(a.current=!1)},[n]),T.useEffect(()=>{const o=s.current;if(!o||!t||n||!r)return;const l=()=>{a.current||(a.current=!0,r())};if(!("IntersectionObserver"in window)){l();return}const u=new IntersectionObserver(c=>{c.some(d=>d.isIntersecting)&&l()},{rootMargin:"240px 0px"});return u.observe(o),()=>u.disconnect()},[t,n,e,r]),!t&&!n?null:i.jsx("div",{ref:s,className:"flex min-h-10 items-center justify-center border-t border-border px-3 py-2 text-xs font-medium text-muted","aria-live":"polite",children:n?`Loading more ${e}...`:`Scroll for more ${e}`})}function Gf({data:e,loading:t,error:n,onBack:r,onRefresh:s,onViewHook:a}){if(t)return i.jsx(qn,{text:"Loading hook detail…"});if(n)return i.jsxs("div",{className:"grid gap-3",children:[i.jsx(Ne,{tone:"error",text:n.message}),i.jsx("button",{type:"button",className:"w-fit rounded border border-border px-3 py-2 text-sm font-semibold",onClick:r,children:"Back to hooks"})]});if(!e)return i.jsx(Z,{text:"Hook detail is not available."});const o=e.hook;return i.jsxs("section",{className:"grid gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsxs("div",{children:[i.jsxs("button",{type:"button",className:"mb-2 inline-flex items-center gap-2 text-sm font-semibold text-primary hover:underline",onClick:r,children:[i.jsx(Bo,{className:"h-4 w-4","aria-hidden":!0}),"Back to hooks"]}),i.jsx("h2",{className:"text-xl font-semibold",children:o.target}),i.jsxs("p",{className:"font-mono text-xs text-muted",children:[o.target_type," webhook #",o.id]})]}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx(lt,{onClick:s}),o.admin_url?i.jsxs("a",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold hover:bg-slate-50",href:Ze(o.admin_url),target:"_blank",rel:"noreferrer",children:[i.jsx(Gt,{className:"h-4 w-4","aria-hidden":!0}),"Open in GitHub"]}):null]})]}),i.jsxs("div",{className:"grid grid-cols-2 gap-3 lg:grid-cols-4",children:[i.jsx(_e,{title:"State",value:o.status,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Deliveries",value:e.stats.deliveries,icon:i.jsx(vn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Retries",value:e.stats.duplicates,icon:i.jsx(ur,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Unsupported",value:e.stats.unsupported,icon:i.jsx(zr,{className:"h-5 w-5"})})]}),i.jsxs(fe,{title:"Sanitized configuration",children:[i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[i.jsx(J,{label:"Active",value:o.active?"yes":"no"}),i.jsx(J,{label:"Content type",value:o.content_type??"unknown"}),i.jsx(J,{label:"SSL verification",value:o.ssl_verify===null||o.ssl_verify===void 0?"unknown":o.ssl_verify?"enabled":"disabled"}),i.jsx(J,{label:"Destination URL",value:o.delivery_url??"unknown"}),i.jsx(J,{label:"GitHub created",value:o.github_created_at??"unknown"}),i.jsx(J,{label:"GitHub updated",value:o.github_updated_at??"unknown"}),i.jsx(J,{label:"Last ping",value:o.last_ping_at??"never"}),i.jsx(J,{label:"Last delivery",value:o.last_event_at??"never"}),i.jsx(J,{label:"Last result",value:o.last_result??"unknown"})]}),i.jsxs("div",{className:"mt-3 rounded-md border border-border p-3",children:[i.jsx("div",{className:"text-xs font-semibold text-muted",children:"Subscribed events"}),i.jsx("div",{className:"mt-2 flex flex-wrap gap-1.5",children:o.events.length?o.events.map(l=>i.jsx("span",{className:"rounded border border-border bg-slate-50 px-2 py-1 font-mono text-xs",children:l},l)):i.jsx("span",{className:"text-sm text-muted",children:"No event snapshot; redeliver a ping."})})]})]}),i.jsx(fe,{title:"Latest observed delivery",children:i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[i.jsx(J,{label:"Event",value:o.last_event_name?`${o.last_event_name}${o.last_action?` · ${o.last_action}`:""}`:"none"}),i.jsx(J,{label:"Repository",value:o.last_repository??"none"}),i.jsx(J,{label:"Delivery ID",value:o.last_delivery_id??"none"})]})}),i.jsx(fe,{title:"Recent deliveries",children:e.recent_deliveries.length?i.jsx(Fl,{deliveries:e.recent_deliveries,onViewHook:a}):i.jsx(Z,{text:"This hook has no retained deliveries."})})]})}function Jf({processes:e,processesLoading:t,processesError:n,systemd:r,systemdLoading:s,systemdError:a,alerts:o,alertsLoading:l,alertsError:u,now:c,onRefreshProcesses:d,onRefreshSystemd:h,onRefreshAlerts:m}){return i.jsxs("section",{className:"grid gap-4","aria-label":"Bridge system",children:[i.jsxs(fe,{title:"Systemd",action:i.jsx(lt,{onClick:h}),children:[a?i.jsx(Ne,{tone:"error",text:a.message}):null,i.jsx(Rx,{data:r,loading:s})]}),i.jsxs(fe,{title:"Process activity",action:i.jsx(lt,{onClick:d}),children:[n?i.jsx(Ne,{tone:"error",text:n.message}):null,i.jsx(Ax,{data:e,loading:t})]}),i.jsxs(fe,{title:"Monitor alerts",action:i.jsx(lt,{onClick:m}),children:[u?i.jsx(Ne,{tone:"error",text:u.message}):null,i.jsx(Lx,{alerts:o,loading:l,now:c})]})]})}function Dn({href:e,active:t,children:n,onNavigate:r}){return i.jsx("a",{className:V("inline-flex h-8 min-w-0 flex-1 items-center justify-center gap-1 rounded-md px-1.5 text-xs font-semibold sm:flex-none sm:gap-1.5 sm:px-3 sm:text-sm [&>span]:truncate [&>svg]:shrink-0",t?"bg-primary text-white shadow-sm":"text-muted hover:bg-slate-50 hover:text-foreground"),href:e,onClick:s=>{!r||s.defaultPrevented||s.button!==0||s.metaKey||s.ctrlKey||s.altKey||s.shiftKey||(s.preventDefault(),r(e))},children:n})}function Xf({jobId:e,detail:t,selectedJob:n,user:r,onBackToDashboard:s,onRetry:a,onDismiss:o,onCancel:l,onRefresh:u}){const[c,d]=T.useState(!1),[h,m]=T.useState(!1),[p,y]=T.useState(!1),w=!!(r!=null&&r.is_admin&&n&&zn(n.status)),j=!!(n&&Oi(n,r)),b=c?"Retrying...":"Retry",S=h?"Dismissing...":"Dismiss",_=p?"Cancelling...":"Cancel";return i.jsxs("div",{className:"grid min-w-0 gap-3 sm:gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[i.jsxs("a",{className:"inline-flex h-9 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50",href:"/",onClick:N=>{N.defaultPrevented||N.button!==0||N.metaKey||N.ctrlKey||N.altKey||N.shiftKey||(N.preventDefault(),s())},children:[i.jsx(Bo,{className:"h-4 w-4","aria-hidden":!0}),"Dashboard"]}),i.jsxs("div",{className:"flex items-center gap-2",children:[w?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:c,onClick:async()=>{if(window.confirm(`Retry job #${e}?`)){d(!0);try{await a(e)}finally{d(!1)}}},children:[i.jsx(Gn,{className:"h-4 w-4","aria-hidden":!0}),b]}):null,w?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md border border-border bg-white px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:h,onClick:async()=>{if(window.confirm(`Dismiss job #${e}?`)){m(!0);try{await o(e)}finally{m(!1)}}},children:[i.jsx(wn,{className:"h-4 w-4","aria-hidden":!0}),S]}):null,j?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md border border-red-200 bg-red-50 px-3 text-sm font-semibold text-red-700 hover:bg-red-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:p,onClick:async()=>{const N=window.prompt(`Cancel job #${e}? Optional reason:`);if(N!==null){y(!0);try{await l(e,N)}finally{y(!1)}}},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),_]}):null,i.jsx(lt,{onClick:u})]})]}),i.jsx(fe,{title:`Job #${e}`,className:"p-3 sm:p-4",children:t})]})}function Yf({selectedJobId:e,selectedJob:t,loading:n,error:r,session:s,sessionEvents:a,transcript:o,now:l}){return t?i.jsx(kx,{job:t,session:s,sessionEvents:a,transcript:o,now:l}):e!==null&&n?i.jsx(Z,{text:"Loading selected job..."}):e!==null&&r?i.jsx(Ne,{tone:"error",text:`Job #${e}: ${r.message}`}):i.jsx(Z,{text:"Select a job to inspect its timeline, worklog and GitHub links."})}function Zf({data:e,loading:t,error:n,repo:r,status:s,user:a,now:o,onRepoChange:l,onStatusChange:u,onApprove:c,onReject:d,onUpdateRuleScope:h,onDeleteRule:m,onRefresh:p}){const y=(e==null?void 0:e.summary)??{},[w,j]=T.useState("proposals"),b=[{id:"proposals",label:"Proposals",count:(e==null?void 0:e.proposals.length)??0},{id:"rules",label:"Rules",count:(e==null?void 0:e.rules.length)??0},{id:"events",label:"Events",count:(e==null?void 0:e.events.length)??0}];return i.jsxs("div",{className:"grid min-w-0 gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsxs("h2",{className:"flex items-center gap-2 text-base font-semibold",children:[i.jsx(Hi,{className:"h-5 w-5 text-muted","aria-hidden":!0}),"Acquired knowledge"]}),i.jsx("p",{className:"text-xs text-muted",children:"Captured feedback, proposed rules and curated agent memory."})]}),i.jsx(lt,{onClick:p})]}),n?i.jsx(Ne,{tone:"error",text:n.message}):null,i.jsxs("section",{className:"grid grid-cols-2 gap-3 lg:grid-cols-4","aria-label":"Knowledge metrics",children:[i.jsx(_e,{title:"Proposed",value:y.proposed??0,icon:i.jsx($o,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Approved",value:y.approved??0,icon:i.jsx(wn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Rules",value:y.rules??0,icon:i.jsx(Ko,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Events",value:y.events??0,icon:i.jsx(bn,{className:"h-5 w-5"})})]}),i.jsx(fe,{title:"Filters",className:"p-3",children:i.jsxs("div",{className:V("grid gap-3",w==="proposals"?"md:grid-cols-[minmax(0,1fr)_220px]":"md:grid-cols-[minmax(0,1fr)]"),children:[i.jsx(Ye,{label:"Repository",children:i.jsxs("select",{className:"control",value:r,onChange:S=>l(S.target.value),children:[i.jsx("option",{value:"",children:"All repositories"}),((e==null?void 0:e.repositories)??[]).map(S=>i.jsx("option",{value:S,children:S},S))]})}),w==="proposals"?i.jsx(Ye,{label:"Proposal status",children:i.jsxs("select",{className:"control",value:s,onChange:S=>u(S.target.value),children:[i.jsx("option",{value:"",children:"All statuses"}),i.jsx("option",{value:"proposed",children:"proposed"}),i.jsx("option",{value:"approved",children:"approved"}),i.jsx("option",{value:"rejected",children:"rejected"}),i.jsx("option",{value:"error",children:"error"})]})}):null]})}),i.jsxs(fe,{title:"Knowledge records",action:i.jsx("div",{className:"flex max-w-full flex-wrap rounded-md border border-border bg-white p-0.5",role:"tablist","aria-label":"Knowledge record type",children:b.map(S=>i.jsxs("button",{className:V("inline-flex h-8 items-center gap-1.5 rounded px-2.5 text-xs font-semibold",w===S.id?"bg-primary text-white":"text-muted hover:bg-slate-50 hover:text-foreground"),type:"button",role:"tab","aria-label":`${S.label} (${S.count})`,"aria-selected":w===S.id,onClick:()=>j(S.id),children:[i.jsx("span",{children:S.label}),i.jsx("span",{className:V("rounded-sm border px-1 font-mono text-[10px]",w===S.id?"border-white/40 text-white":"border-border text-muted"),children:S.count})]},S.id))}),children:[w==="proposals"?i.jsx(ex,{proposals:(e==null?void 0:e.proposals)??[],loading:t,isAdmin:!!(a!=null&&a.is_admin),now:o,onApprove:c,onReject:d}):null,w==="rules"?i.jsx(rx,{rules:(e==null?void 0:e.rules)??[],loading:t,now:o,onUpdateRuleScope:h,onDeleteRule:m}):null,w==="events"?i.jsx(ix,{events:(e==null?void 0:e.events)??[],loading:t,now:o}):null]})]})}function ex({proposals:e,loading:t,isAdmin:n,now:r,onApprove:s,onReject:a}){const[o,l]=T.useState(null);return t&&e.length===0?i.jsx(Z,{text:"Loading proposals..."}):e.length===0?i.jsx(Z,{text:"No proposals match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(u=>i.jsxs("article",{className:"grid min-w-0 gap-2 rounded-md border border-border bg-white p-3",children:[i.jsx(Bl,{scope:u.scope,type:u.type,confidence:u.confidence,status:u.status,timestamp:u.updated_at,now:r}),i.jsx("p",{className:"min-w-0 break-words text-sm font-medium [overflow-wrap:anywhere]",children:u.rule||u.reason||"No reusable rule proposed."}),u.reason?i.jsx("p",{className:"min-w-0 break-words text-xs text-muted [overflow-wrap:anywhere]",children:u.reason}):null,u.source_event?i.jsx(tx,{event:u.source_event}):i.jsxs("p",{className:"font-mono text-xs text-muted",children:["Source event ",u.event_id]}),u.error?i.jsx(Ne,{tone:"error",text:u.error}):null,n&&u.status==="proposed"?i.jsxs("div",{className:"flex flex-wrap gap-2",children:[i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:opacity-60",type:"button",disabled:o===u.id,onClick:async()=>{l(u.id);try{await s(u.id)}finally{l(null)}},children:[i.jsx(wn,{className:"h-4 w-4","aria-hidden":!0}),"Approve"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:o===u.id,onClick:async()=>{l(u.id);try{await a(u.id)}finally{l(null)}},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Reject"]})]}):null]},u.id))})}function tx({event:e}){const t=e.trigger_actor||(e.actor!=="github"?e.actor:null);return i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-border bg-slate-50 px-2 py-1.5",children:[i.jsx(Cn,{actor:t,avatarUrl:e.trigger_actor_avatar_url,framed:!0}),e.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border bg-white px-2 text-xs font-semibold text-foreground hover:bg-slate-50",href:Sn(e.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",e.source_job_id]}):null,e.github_urls.length>0?i.jsx(Xn,{urls:e.github_urls,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]})}function nx(e){const t=[{value:"global",label:"global"}];if(e.startsWith("repo:")){const n=e.slice(5),[r,s]=n.split("/",2);r&&s&&(t.push({value:`org:${r}`,label:`org:${r}`}),t.push({value:`repo:${r}/${s}`,label:`repo:${r}/${s}`}))}else e.startsWith("org:")&&t.push({value:e,label:e});return t.some(n=>n.value===e)||t.push({value:e,label:e}),t}function rx({rules:e,loading:t,now:n,onUpdateRuleScope:r,onDeleteRule:s}){const[a,o]=T.useState(null),[l,u]=T.useState(null),[c,d]=T.useState("");return t&&e.length===0?i.jsx(Z,{text:"Loading curated rules..."}):e.length===0?i.jsx(Z,{text:"No curated rules match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(h=>{const m=h.source_event_details??[],p=m[0],y=p?p.trigger_actor||(p.actor!=="github"?p.actor:null):null,w=m.flatMap(N=>N.github_urls??[]),j=nx(h.scope),b=l===h.id,S=a===h.id,_=!!h.can_manage;return i.jsxs("article",{className:"grid min-w-0 gap-2 rounded-md border border-border bg-white p-3",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsx(Bl,{scope:h.scope,type:h.type,confidence:h.confidence,status:`${h.observations} observation${h.observations===1?"":"s"}`,timestamp:h.last_seen,now:n}),_?i.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[b?i.jsxs(i.Fragment,{children:[i.jsx(Ye,{label:"Scope",children:i.jsx("select",{className:"control h-8 min-w-[180px] py-1 text-xs",value:c,disabled:S,onChange:N=>d(N.target.value),children:j.map(N=>i.jsx("option",{value:N.value,children:N.label},N.value))})}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S||c===h.scope,title:"Save scope",onClick:async()=>{if(c!==h.scope){o(h.id);try{await r(h.id,c),u(null)}finally{o(null)}}},children:[i.jsx(ic,{className:"h-4 w-4","aria-hidden":!0}),"Save"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-muted hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S,title:"Cancel scope edit",onClick:()=>{u(null),d("")},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Cancel"]})]}):i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S,title:"Edit scope",onClick:()=>{u(h.id),d(h.scope)},children:[i.jsx(rc,{className:"h-4 w-4","aria-hidden":!0}),"Edit"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-red-200 px-3 text-sm font-semibold text-red-700 hover:bg-red-50 disabled:opacity-60",type:"button",disabled:S,onClick:async()=>{if(window.confirm("Delete this curated rule?")){o(h.id);try{await s(h.id)}finally{o(null)}}},children:[i.jsx(ki,{className:"h-4 w-4","aria-hidden":!0}),"Delete"]})]}):null]}),i.jsx("p",{className:"min-w-0 break-words text-sm font-medium [overflow-wrap:anywhere]",children:h.rule}),i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[i.jsx(Cn,{actor:y,avatarUrl:p==null?void 0:p.trigger_actor_avatar_url,framed:!0}),p!=null&&p.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border px-2 text-xs font-semibold text-foreground hover:bg-white",href:Sn(p.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",p.source_job_id]}):null,w.length>0?i.jsx(Xn,{urls:w,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]})]},h.id)})})}function ix({events:e,loading:t,now:n}){return t&&e.length===0?i.jsx(Z,{text:"Loading captured events..."}):e.length===0?i.jsx(Z,{text:"No captured feedback events match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(r=>{const s=r.trigger_actor||(r.actor!=="github"?r.actor:null);return i.jsxs("details",{className:"group rounded-md border border-border bg-white",children:[i.jsxs("summary",{className:"grid cursor-pointer list-none gap-2 px-3 py-2 marker:hidden hover:bg-slate-50",children:[i.jsxs("div",{className:"flex min-w-0 items-center justify-between gap-2",children:[i.jsxs("span",{className:"inline-flex min-w-0 items-center gap-2 font-mono text-xs font-semibold text-muted",children:[i.jsx(yn,{className:"h-3.5 w-3.5 shrink-0 transition-transform group-open:rotate-180","aria-hidden":!0}),i.jsx("span",{className:"truncate",children:Dl(r.scope)})]}),i.jsx("span",{className:"shrink-0 font-mono text-xs text-muted",children:i.jsx(Ie,{value:r.occurred_at,relative:!0,now:n})})]}),i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[i.jsx(Cn,{actor:s,avatarUrl:r.trigger_actor_avatar_url,framed:!0}),r.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border px-2 text-xs font-semibold text-foreground hover:bg-white",href:Sn(r.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",r.source_job_id]}):null,r.github_urls.length>0?i.jsx(Xn,{urls:r.github_urls,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]}),i.jsx("p",{className:"line-clamp-2 break-words text-sm [overflow-wrap:anywhere]",children:r.comment})]}),i.jsxs("div",{className:"grid gap-2 border-t border-border px-3 py-2",children:[i.jsxs("div",{children:[i.jsx("h3",{className:"mb-1 text-xs font-semibold text-muted",children:"GitHub links"}),r.github_urls.length>0?i.jsx(Xn,{urls:r.github_urls}):i.jsx("p",{className:"text-xs text-muted",children:"No links recorded."})]}),i.jsx("pre",{className:"max-h-72 overflow-auto rounded-md bg-slate-950 px-3 py-2 font-mono text-xs leading-relaxed text-slate-100",children:JSON.stringify(r.context,null,2)})]})]},r.id)})})}function sx({tokens:e,loading:t,error:n,user:r,ownerOptions:s,dashboardUrl:a,dashboardUrlSource:o,now:l,onCreate:u,onUpdateOwner:c,onRevoke:d,onRefresh:h}){const[m,p]=T.useState(""),[y,w]=T.useState(""),[j,b]=T.useState(!1),[S,_]=T.useState(null),[N,q]=T.useState(null),[k,B]=T.useState(null),[M,v]=T.useState(""),F=e??[],L=s.find(E=>E.login===y);T.useEffect(()=>{var E;r!=null&&r.is_admin&&(y&&s.some(O=>O.login===y)||w((r==null?void 0:r.login)||((E=s[0])==null?void 0:E.login)||""))},[s,r==null?void 0:r.is_admin,r==null?void 0:r.login,y]);const P=(a||(typeof window>"u"?"":window.location.origin)).replace(/\/$/,""),G=`${P}/mcp`,z=`${P}/api/mcp`;return i.jsxs("div",{className:"grid min-w-0 gap-4",children:[i.jsx(zl,{icon:i.jsx(Tr,{className:"h-5 w-5 text-muted","aria-hidden":!0}),title:"MCP access",subtitle:r!=null&&r.is_admin?"Issue and revoke read-only tokens for any dashboard user.":"Issue and revoke read-only tokens linked to your user.",action:i.jsx(lt,{onClick:h})}),n?i.jsx(Ne,{tone:"error",text:n.message}):null,M?i.jsx(Ne,{tone:"error",text:M}):null,i.jsx(ax,{dashboardUrl:G,endpointUrl:z,dashboardUrlSource:o??"request"}),k?i.jsxs("section",{className:"rounded-md border border-emerald-300 bg-emerald-50 p-3 text-emerald-950","aria-label":"Created MCP token",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-sm font-semibold",children:"Token created"}),i.jsx("p",{className:"mt-1 text-xs text-emerald-800",children:"This secret is shown once. Store it in the local agent environment before leaving this page."})]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-emerald-300 bg-white px-3 text-sm font-semibold text-emerald-900 hover:bg-emerald-100",type:"button",onClick:()=>B(null),children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Hide"]})]}),i.jsx("pre",{className:"mt-3 overflow-auto rounded bg-emerald-950 px-3 py-2 font-mono text-xs text-emerald-50",children:k.token})]}):null,i.jsx(fe,{title:"Create token",children:i.jsxs("form",{className:r!=null&&r.is_admin?"grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(12rem,16rem)_auto]":"grid gap-3 md:grid-cols-[minmax(0,1fr)_auto]",onSubmit:async E=>{E.preventDefault();const O=m.trim();if(O){b(!0),v("");try{const Q=await u(O,r!=null&&r.is_admin?y:void 0);B(Q),p("")}catch(Q){v(Q instanceof Error?Q.message:String(Q))}finally{b(!1)}}},children:[i.jsx(Ye,{label:"Token name",children:i.jsx("input",{className:"control",value:m,placeholder:"local agent",disabled:j,onChange:E=>p(E.target.value)})}),r!=null&&r.is_admin?i.jsxs(Ye,{label:"Owner",children:[i.jsx(ql,{ariaLabel:"Owner",value:y,ownerOptions:s,disabled:j||s.length===0,selectedSuffix:E=>E.login===(r==null?void 0:r.login)?" (you)":"",emptyLabel:"No known users",onChange:w}),L?i.jsxs("span",{className:"font-normal text-muted",children:["Token will be linked to @",L.login,"."]}):null]}):null,i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 self-end rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60",type:"submit",disabled:j||!m.trim()||!!(r!=null&&r.is_admin&&!y),children:[i.jsx(Tr,{className:"h-4 w-4","aria-hidden":!0}),j?"Creating...":"Create token"]})]})}),i.jsx(fe,{title:"Active tokens",children:i.jsx(ox,{tokens:F,loading:t,now:l,ownerOptions:s,canManageOwners:!!(r!=null&&r.is_admin),revokingId:S,updatingOwnerId:N,onUpdateOwner:async(E,O)=>{q(E),v("");try{await c(E,O)}catch(Q){v(Q instanceof Error?Q.message:String(Q))}finally{q(null)}},onRevoke:async E=>{if(window.confirm("Revoke this MCP token?")){_(E),v("");try{await d(E)}catch(O){v(O instanceof Error?O.message:String(O))}finally{_(null)}}}})})]})}function ax({dashboardUrl:e,endpointUrl:t,dashboardUrlSource:n}){const r=n==="configured"?"Configured public URL":n==="forwarded"?"Forwarded public URL":"Needs public URL",s=n==="request",a=s?"Set GITHUB_AGENT_BRIDGE_DASHBOARD_PUBLIC_URL or forward X-Forwarded-* headers":e,o=s?"Public dashboard URL required before connecting remote agents":t,u=`{ +`)}function gf(e){const t=[];for(const n of e){const r=t[t.length-1];if(r&&Or(n.event_type)&&r.eventType===n.event_type){r.count+=1,r.meta=n.ts,r.detail=Ol([r.detail,n.detail]),r.summary=Mr(n.summary,r.detail,r.count);continue}t.push({id:String(n.id),badge:n.event_type,meta:n.ts,summary:Or(n.event_type)?Mr(n.summary,n.detail):n.summary,detail:n.detail,eventType:n.event_type,count:1})}return t}function bf(e){const t=[];return e.forEach((n,r)=>{const s=t[t.length-1];if(s&&Or(n.kind)&&s.kind===n.kind){s.count+=1,s.meta=n.timestamp,s.text=Ol([s.text,n.text]),s.summary=Mr(`${n.role} · ${n.kind}`,s.text,s.count);return}t.push({id:`${n.timestamp??"entry"}-${r}`,badge:n.title,meta:n.timestamp,summary:Or(n.kind)?Mr(`${n.role} · ${n.kind}`,n.text):`${n.role} · ${n.kind}`,text:n.text,kind:n.kind,count:1})}),t}function no(e,t,n,r){return e==="openclaw_stdout"?!1:t||n>=r-2}function yf(e){return{pending:{badge:"border-amber-300 bg-amber-50 text-amber-800",dot:"bg-amber-500"},running:{badge:"border-blue-300 bg-blue-50 text-blue-700",dot:"bg-blue-600"},blocked:{badge:"border-red-300 bg-red-50 text-red-700",dot:"bg-red-600"},denied:{badge:"border-red-300 bg-red-50 text-red-700",dot:"bg-red-600"},done:{badge:"border-emerald-300 bg-emerald-50 text-emerald-700",dot:"bg-emerald-600"},waiting_approval:{badge:"border-slate-300 bg-slate-50 text-slate-700",dot:"bg-slate-500"}}[e]??{badge:"border-slate-300 bg-slate-50 text-slate-700",dot:"bg-slate-500"}}function wf(e,t){const n=new URLSearchParams;for(const[r,s]of Object.entries(e))s.trim()&&n.set(r,s.trim());return n.set("limit",String(t)),`/api/jobs?${n.toString()}`}function vf(e,t,n=50){const r=new URLSearchParams;return e.trim()&&r.set("repo",e.trim()),t.trim()&&r.set("status",t.trim()),r.set("limit",String(n)),`/api/knowledge?${r.toString()}`}function jf(e){return{timeseries:e==="overview",hooks:e==="hooks",deliveries:e==="deliveries"}}function kf(e,t,n="day"){return`/api/webhooks/github/timeseries?${new URLSearchParams({from:e,to:t,bucket:n}).toString()}`}function Nf(e=50,t){const n=new URLSearchParams({limit:String(e)});return t&&n.set("cursor",t),`/api/webhooks/github/hooks?${n.toString()}`}function Sf(e=50,t,n){const r=new URLSearchParams({limit:String(e)});t&&r.set("cursor",t);for(const[s,a]of Object.entries(n??{}))a!=null&&a.trim()&&r.set(s,a.trim());return`/api/webhooks/github/deliveries?${r.toString()}`}function Sr(e=new Date){return{from:new Date(e.getTime()-720*60*60*1e3).toISOString(),to:e.toISOString()}}function Cf(e=Al){return`/api/metrics/summary?timezone=${encodeURIComponent(e)}`}function Ze(e){try{const t=new URL(e);return t.protocol==="https:"||t.protocol==="http:"?t.href:"#"}catch{return"#"}}function Rr(){return"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}function _f(e){return!!(e&&typeof e=="object"&&"type"in e&&e.type==="github-agent-bridge:push")}function Ef(e){const t="=".repeat((4-e.length%4)%4),n=(e+t).replace(/-/g,"+").replace(/_/g,"/"),r=window.atob(n),s=new Uint8Array(r.length);for(let a=0;an.id===t.id)?e:[...e,t]}function Rf(e,t){const n=ro(t);return e.some(r=>ro(r)===n)?e:[...e,t]}function ro(e){return`${e.timestamp??""}:${e.role}:${e.kind}:${e.title}:${e.text}`}function If(e){return["claimed","dispatch_started","dispatch_finished","done","blocked","denied","waiting_approval"].includes(e)}function zn(e){return["blocked","denied","waiting_approval"].includes(e)}function Oi(e,t){return e.status!=="running"?!1:t!=null&&t.is_admin?!0:!!(t!=null&&t.login&&e.trigger_actor&&t.login.toLowerCase()===e.trigger_actor.toLowerCase())}function Tf(e=window.location.pathname){const t=e.match(/^\/jobs\/(\d+)\/?$/);return t?Number(t[1]):null}function Af(e=window.location.pathname){return/^\/knowledge\/?$/.test(e)}function Lf(e=window.location.pathname){return/^\/mcp\/?$/.test(e)}function Mf(e=window.location.pathname){return/^\/system\/?$/.test(e)}function Of(e=window.location.pathname){const t=e.match(/^\/webhooks\/hooks\/([^/]+)\/?$/);return t?decodeURIComponent(t[1]):null}function si(e=window.location.pathname){return/^\/webhooks(?:\/hooks\/[^/]+)?\/?$/.test(e)}function Dl(e){return e.startsWith("repo:")?e.slice(5):e}function io(e){return Object.values(e).some(t=>t.trim()!=="")}function Df(e){return[{key:"status",label:"Status",value:e.status},{key:"repo",label:"Repo",value:e.repo},{key:"thread",label:"Thread",value:e.thread},{key:"action",label:"Action",value:e.action},{key:"actor",label:"Actor",value:e.actor.trim()?`@${e.actor.trim().replace(/^@/,"")}`:""},{key:"intent",label:"Intent",value:e.intent}].filter(t=>t.value.trim()!=="")}function Ff(){var cs,ds,hs,ps,ms,fs,xs,gs,bs,ys,ws,vs,js,ks,Ns,Ss,Cs,_s,Es,Ps,Rs,Is,Ts,As,Ls,Ms,Os,Ds,Fs,zs,qs,Bs,Us,$s,Hs,Ks,Qs,Vs,Ws,Gs,Js,Xs,Ys;const e=Do(),[t,n]=T.useState(Mi),[r,s]=T.useState(to),a=T.useRef(!1),[o,l]=T.useState(""),[u,c]=T.useState("proposed"),[d,h]=T.useState("overview"),[m,p]=T.useState({hook_id:"",event_name:"",repository:"",result:""}),[y,w]=T.useState(()=>Sr()),[j,b]=T.useState(null),[S,_]=T.useState(""),[N,q]=T.useState(()=>window.location.pathname),[k,B]=T.useState(null),M=Tf(N),v=M!==null,F=Af(N),L=Lf(N),P=Mf(N),G=si(N),z=Of(N),E=!v&&!F&&!L&&!P&&!G,O=M,Q=ge({queryKey:["metrics",Al],queryFn:()=>ee(Cf()),enabled:E||P}),he=ge({queryKey:["dashboard-status"],queryFn:()=>ee("/api/status")}),se=ge({queryKey:["me"],queryFn:()=>ee("/api/me"),refetchInterval:!1}),f=G&&!!((ds=(cs=se.data)==null?void 0:cs.user)!=null&&ds.is_admin&&((hs=he.data)!=null&&hs.webhook_configured)),ue=jf(d),Se=ge({queryKey:["web-push-config"],queryFn:()=>ee("/api/web-push/config"),enabled:!!((ps=se.data)!=null&&ps.user)}),x=ge({queryKey:["about"],queryFn:()=>ee("/api/about")}),De=ge({queryKey:["job-actors"],queryFn:()=>ee("/api/jobs/actors"),enabled:E}),we=ge({queryKey:["jobs",t,r],queryFn:()=>ee(wf(t,r)),enabled:E,placeholderData:A=>A}),me=ge({queryKey:["processes"],queryFn:()=>ee("/api/processes"),enabled:P}),et=ge({queryKey:["systemd"],queryFn:()=>ee("/api/systemd"),enabled:P}),Fe=ge({queryKey:["alerts"],queryFn:()=>ee("/api/alerts"),enabled:P}),Ve=ge({queryKey:["webhook-summary"],queryFn:()=>ee("/api/webhooks/github/summary"),enabled:f}),tt=ge({queryKey:["webhook-timeseries",y.from,y.to,"day"],queryFn:()=>ee(kf(y.from,y.to)),enabled:f&&ue.timeseries}),At=ge({queryKey:["webhook-exceptions"],queryFn:()=>ee("/api/webhooks/github/exceptions"),enabled:f&&ue.timeseries}),ct=pa({queryKey:["webhook-hooks"],queryFn:({pageParam:A})=>ee(Nf(50,A)),initialPageParam:null,getNextPageParam:A=>A.next_cursor??void 0,enabled:f&&ue.hooks&&z===null}),dt=pa({queryKey:["webhook-deliveries",m],queryFn:({pageParam:A})=>ee(Sf(50,A,m)),initialPageParam:null,getNextPageParam:A=>A.next_cursor??void 0,enabled:f&&ue.deliveries&&z===null}),Yt=ge({queryKey:["webhook-hook",z],queryFn:()=>ee(`/api/webhooks/github/hooks/${encodeURIComponent(z??"")}`),enabled:f&&z!==null}),Lt=ge({queryKey:["knowledge",o,u],queryFn:()=>ee(vf(o,u)),enabled:F}),Mt=ge({queryKey:["mcp-tokens"],queryFn:()=>ee("/api/mcp/tokens"),enabled:L&&!!((ms=se.data)!=null&&ms.user)}),pr=ge({queryKey:["mcp-users"],queryFn:()=>ee("/api/mcp/users"),enabled:L&&!!((fs=se.data)!=null&&fs.user)}),Zt=ge({queryKey:["job",O],queryFn:()=>ee(`/api/jobs/${O}`),enabled:O!==null}),_n=ge({queryKey:["job-session",O],queryFn:()=>ee(`/api/jobs/${O}/session`),enabled:O!==null}),En=ge({queryKey:["job-session-events",O],queryFn:()=>ee(`/api/jobs/${O}/session/events`),enabled:O!==null}),mr=ge({queryKey:["job-session-transcript",O],queryFn:()=>ee(`/api/jobs/${O}/session/transcript`),enabled:O!==null}),fr=T.useCallback(async A=>{const ae=await ee(`/api/jobs/${A}/retry`,{method:"POST"});e.setQueryData(["job",A],{job:ae.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]})},[e]),xr=T.useCallback(async A=>{const ae=await ee(`/api/jobs/${A}/dismiss`,{method:"POST"});e.setQueryData(["job",A],{job:ae.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]})},[e]),gr=T.useCallback(async(A,ae)=>{const pe=await ee(`/api/jobs/${A}/cancel`,{method:"POST",body:JSON.stringify({reason:ae||""})});e.setQueryData(["job",A],{job:pe.job}),e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["metrics"]}),e.invalidateQueries({queryKey:["dashboard-status"]})},[e]),br=T.useCallback(async(A,ae)=>{await ee(`/api/knowledge/proposals/${encodeURIComponent(A)}/${ae}`,{method:"POST"}),e.invalidateQueries({queryKey:["knowledge"]}),e.invalidateQueries({queryKey:["dashboard-status"]})},[e]),C=T.useCallback(async A=>{await ee(`/api/knowledge/rules/${encodeURIComponent(A)}`,{method:"DELETE"}),e.invalidateQueries({queryKey:["knowledge"]})},[e]),I=T.useCallback(async(A,ae)=>{await ee(`/api/knowledge/rules/${encodeURIComponent(A)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({scope:ae})}),e.invalidateQueries({queryKey:["knowledge"]})},[e]),H=T.useCallback(async(A,ae)=>{const pe=await ee("/api/mcp/tokens",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:A,user_login:ae||void 0})});return e.invalidateQueries({queryKey:["mcp-tokens"]}),pe},[e]),X=T.useCallback(async(A,ae)=>{await ee(`/api/mcp/tokens/${encodeURIComponent(A)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({user_login:ae})}),e.invalidateQueries({queryKey:["mcp-tokens"]}),e.invalidateQueries({queryKey:["mcp-users"]})},[e]),ie=T.useCallback(async A=>{await ee(`/api/mcp/tokens/${encodeURIComponent(A)}`,{method:"DELETE"}),e.invalidateQueries({queryKey:["mcp-tokens"]})},[e]),Pe=T.useCallback(async A=>{const ae={refresh:"/api/autoupdate/refresh",apply:"/api/autoupdate/apply",complete:"/api/autoupdate/complete-pending"}[A];b(A),_("");try{await ee(ae,{method:"POST"}),e.invalidateQueries({queryKey:["dashboard-status"]})}catch(pe){e.invalidateQueries({queryKey:["dashboard-status"]}),_(pe instanceof Error?pe.message:String(pe))}finally{b(null)}},[e]),ht=T.useCallback(async()=>{var Zs;const A=(Zs=Se.data)==null?void 0:Zs.public_key;if(!A)throw new Error("web_push_not_configured");if(!Rr())throw new Error("web_push_not_supported");if(await window.Notification.requestPermission()!=="granted")throw new Error("notification_permission_denied");const pe=await navigator.serviceWorker.register("/service-worker.js"),ru=await pe.pushManager.getSubscription()??await pe.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Ef(A)});await ee("/api/web-push/subscriptions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(ru.toJSON())}),e.invalidateQueries({queryKey:["web-push-config"]})},[e,(xs=Se.data)==null?void 0:xs.public_key]),We=T.useCallback(async()=>{if(!Rr())return;const ae=await(await navigator.serviceWorker.ready).pushManager.getSubscription();if(!ae)return;const pe=ae.endpoint;await ae.unsubscribe(),await ee("/api/web-push/subscriptions",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({endpoint:pe})}),e.invalidateQueries({queryKey:["web-push-config"]})},[e]);T.useEffect(()=>{var A;!((A=Se.data)!=null&&A.status.enabled)||!Rr()||navigator.serviceWorker.register("/service-worker.js").catch(()=>{})},[(gs=Se.data)==null?void 0:gs.status.enabled]),T.useEffect(()=>{if(O===null)return;const A=new EventSource(`/api/jobs/${O}/session/stream`);return A.addEventListener("session_event",ae=>{const pe=Dr(ae);pe&&(e.setQueryData(["job-session-events",O],bt=>({events:Pf((bt==null?void 0:bt.events)??[],pe)})),If(pe.event_type)&&(e.invalidateQueries({queryKey:["job",O]}),e.invalidateQueries({queryKey:["jobs"]})))}),A.addEventListener("transcript_entry",ae=>{const pe=Dr(ae);!pe||pe.job_id!==O||e.setQueryData(["job-session-transcript",O],bt=>({entries:Rf((bt==null?void 0:bt.entries)??[],pe.entry)}))}),A.onerror=()=>{e.invalidateQueries({queryKey:["job",O]}),e.invalidateQueries({queryKey:["job-session-events",O]}),e.invalidateQueries({queryKey:["job-session-transcript",O]})},()=>A.close()},[O,e]),T.useEffect(()=>{const A=()=>{si(window.location.pathname)&&w(Sr()),q(window.location.pathname)};return window.addEventListener("popstate",A),()=>window.removeEventListener("popstate",A)},[]),T.useEffect(()=>{if(!("serviceWorker"in navigator))return;const A=ae=>{if(!_f(ae.data))return;const pe={...ae.data.payload,id:Date.now(),receivedAt:Date.now()};B(pe),pe.job_id&&(e.invalidateQueries({queryKey:["jobs"]}),e.invalidateQueries({queryKey:["job",pe.job_id]}),e.invalidateQueries({queryKey:["metrics"]}))};return navigator.serviceWorker.addEventListener("message",A),()=>navigator.serviceWorker.removeEventListener("message",A)},[e]),T.useEffect(()=>{if(!k)return;const A=window.setTimeout(()=>B(null),12e3);return()=>window.clearTimeout(A)},[k]);const Ot=T.useCallback(A=>{window.history.pushState({},"",Sn(A)),q(window.location.pathname)},[]),$e=T.useCallback(A=>{window.history.pushState({},"",A),si(A)&&w(Sr()),q(window.location.pathname)},[]),be=((bs=Q.data)==null?void 0:bs.metrics.status_counts)??{},Ge=((ys=we.data)==null?void 0:ys.jobs)??[],Je=T.useCallback(A=>{n(A),s(to),a.current=!1},[]);T.useEffect(()=>{we.isFetching||(a.current=!1)},[we.isFetching]);const Gl=T.useCallback(()=>{a.current||(a.current=!0,s(A=>A+uf))},[]),gt=O?((ws=Zt.data)==null?void 0:ws.job)??null:null,Jl=Ge.some(A=>A.status==="running"||A.status==="pending")||(gt==null?void 0:gt.status)==="running"||(gt==null?void 0:gt.status)==="pending"||!!((vs=me.data)!=null&&vs.running_jobs.length),Pn=ff(Jl),Xl=i.jsx(Yf,{selectedJobId:O,selectedJob:gt,loading:Zt.isLoading,error:Zt.error,session:(js=_n.data)==null?void 0:js.session,sessionEvents:(ks=En.data)==null?void 0:ks.events,transcript:(Ns=mr.data)==null?void 0:Ns.entries,now:Pn}),Yl=((Ss=ct.data)==null?void 0:Ss.pages.flatMap(A=>A.hooks))??[],Zl=((Cs=dt.data)==null?void 0:Cs.pages.flatMap(A=>A.deliveries))??[],eu=d==="overview"?tt.isLoading:d==="hooks"?ct.isLoading:dt.isLoading,tu=d==="overview"?tt.error:d==="hooks"?ct.error:dt.error,nu=()=>{Ve.refetch(),d==="overview"&&At.refetch(),d==="overview"&&w(Sr()),d==="hooks"&&ct.refetch(),d==="deliveries"&&dt.refetch()};return i.jsxs("div",{className:"min-h-screen bg-background text-foreground",children:[i.jsx("header",{className:"border-b border-slate-800 bg-slate-950 text-white",children:i.jsxs("div",{className:"mx-auto flex w-full max-w-[1440px] items-center justify-between gap-3 px-4 py-4 md:px-6",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsx("h1",{className:"truncate text-xl font-semibold",children:"GitHub Agent Bridge"}),i.jsx(zf,{about:x.data})]}),i.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[i.jsx(cx,{config:Se.data,loading:Se.isLoading,onEnable:ht,onDisable:We}),i.jsx(ux,{user:(_s=se.data)==null?void 0:_s.user,loading:se.isLoading})]})]})}),i.jsxs("main",{className:"mx-auto grid w-full max-w-[1440px] gap-4 px-3 py-4 sm:px-4 md:px-6 md:py-5",children:[i.jsx(Kf,{isDashboardRoute:E,isSystemRoute:P,isKnowledgeRoute:F,isMcpRoute:L,isWebhooksRoute:G,showWebhooks:!!((Ps=(Es=se.data)==null?void 0:Es.user)!=null&&Ps.is_admin&&((Rs=he.data)!=null&&Rs.webhook_configured)),knowledgeBadgeCount:((As=(Ts=(Is=he.data)==null?void 0:Is.metrics)==null?void 0:Ts.knowledge)==null?void 0:As.proposed)??0,onNavigate:$e}),i.jsx(dx,{notification:k,onDismiss:()=>B(null),onNavigate:$e}),M!==null?i.jsx(Xf,{jobId:M,detail:Xl,selectedJob:gt,user:(Ls=se.data)==null?void 0:Ls.user,onBackToDashboard:()=>$e("/"),onRetry:fr,onDismiss:xr,onCancel:gr,onRefresh:()=>{Zt.refetch(),_n.refetch(),En.refetch(),mr.refetch()}}):F?i.jsx(Zf,{data:Lt.data,loading:Lt.isLoading,error:Lt.error,repo:o,status:u,user:(Ms=se.data)==null?void 0:Ms.user,now:Pn,onRepoChange:l,onStatusChange:c,onApprove:A=>br(A,"approve"),onReject:A=>br(A,"reject"),onUpdateRuleScope:I,onDeleteRule:C,onRefresh:()=>Lt.refetch()}):L?i.jsx(sx,{tokens:(Os=Mt.data)==null?void 0:Os.tokens,loading:Mt.isLoading,error:Mt.error,user:(Ds=se.data)==null?void 0:Ds.user,ownerOptions:((Fs=pr.data)==null?void 0:Fs.users)??[],dashboardUrl:(zs=he.data)==null?void 0:zs.dashboard_url,dashboardUrlSource:(qs=he.data)==null?void 0:qs.dashboard_url_source,now:Pn,onCreate:H,onUpdateOwner:X,onRevoke:ie,onRefresh:()=>Mt.refetch()}):G?z?i.jsx(Gf,{data:Yt.data,loading:Yt.isLoading,error:Yt.error,onBack:()=>{h("hooks"),$e("/webhooks")},onRefresh:()=>Yt.refetch(),onViewHook:A=>$e(`/webhooks/hooks/${encodeURIComponent(A)}`)}):i.jsx(Qf,{summary:Ve.data,timeseries:(Bs=tt.data)==null?void 0:Bs.points,exceptions:(Us=At.data)==null?void 0:Us.exceptions,hooks:Yl,deliveries:Zl,section:d,summaryLoading:Ve.isLoading,sectionLoading:eu,loadingMore:d==="hooks"?ct.isFetchingNextPage:dt.isFetchingNextPage,hasMore:d==="hooks"?ct.hasNextPage:dt.hasNextPage,deliveryFilters:m,error:Ve.error??tu,onSectionChange:h,onLoadMore:()=>d==="hooks"?ct.fetchNextPage():dt.fetchNextPage(),onDeliveryFiltersChange:p,onViewHook:A=>$e(`/webhooks/hooks/${encodeURIComponent(A)}`),onRefresh:nu}):P?i.jsx(Jf,{processes:me.data,processesLoading:me.isLoading,processesError:me.error,systemd:et.data,systemdLoading:et.isLoading,systemdError:et.error,alerts:($s=Fe.data)==null?void 0:$s.alerts,alertsLoading:Fe.isLoading,alertsError:Fe.error,now:Pn,onRefreshProcesses:()=>me.refetch(),onRefreshSystemd:()=>et.refetch(),onRefreshAlerts:()=>Fe.refetch()}):i.jsxs(i.Fragment,{children:[Q.error?i.jsx(Ne,{tone:"error",text:Q.error.message}):null,he.error?i.jsx(Ne,{tone:"error",text:he.error.message}):null,i.jsx(qf,{state:(Hs=he.data)==null?void 0:Hs.autoupdate,isAdmin:!!((Qs=(Ks=se.data)==null?void 0:Ks.user)!=null&&Qs.is_admin),runningAction:j,actionError:S,onRefresh:()=>Pe("refresh"),onApply:()=>Pe("apply"),onCompletePending:()=>Pe("complete")}),i.jsxs("section",{className:"grid grid-cols-2 gap-3 xl:grid-cols-4","aria-label":"Summary metrics",children:[i.jsx(_e,{title:"Pending",value:be.pending??0,icon:i.jsx($o,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Running",value:be.running??0,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Blocked",value:be.blocked??0,icon:i.jsx(zr,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Done",value:be.done??0,icon:i.jsx(wn,{className:"h-5 w-5"})})]}),i.jsxs("section",{className:"grid gap-3",children:[i.jsx(hx,{count:Ge.length,limit:r,loading:we.isLoading,onRefresh:()=>we.refetch()}),i.jsxs(fe,{title:"Recent jobs",flushHeader:!0,children:[i.jsx(px,{filters:t,actorOptions:((Vs=De.data)==null?void 0:Vs.actors)??[],onChange:Je}),we.error?i.jsx(Ne,{tone:"error",text:we.error.message}):null,i.jsx(fx,{jobs:Ge,loading:we.isLoading,loadingMore:we.isFetching&&!we.isLoading,hasMore:Ge.length>=r,onLoadMore:Gl,onViewJob:Ot,now:Pn,user:(Ws=se.data)==null?void 0:Ws.user,onRetry:fr,onDismiss:xr,onCancel:gr})]}),i.jsx(fe,{title:"Runtime usage",action:i.jsx(lt,{onClick:()=>Q.refetch()}),children:i.jsx(Ex,{usage:(Gs=Q.data)==null?void 0:Gs.metrics.runtime_usage,loading:Q.isLoading,totalJobs:lo(be)})})]}),i.jsxs("section",{className:"grid gap-4 xl:grid-cols-3",children:[i.jsx(fe,{title:"Runtime percentiles",children:i.jsx(oo,{label:"runtime",values:(Js=Q.data)==null?void 0:Js.metrics.runtime_seconds})}),i.jsx(fe,{title:"Jobs per day",children:i.jsx(_x,{values:(Xs=Q.data)==null?void 0:Xs.metrics.by_created_day,loading:Q.isLoading,totalJobs:lo(be)})}),i.jsx(fe,{title:"Queue wait percentiles",children:i.jsx(oo,{label:"queue wait",values:(Ys=Q.data)==null?void 0:Ys.metrics.queue_wait_seconds})})]})]})]})]})}function zf({about:e}){const t=e!=null&&e.version?`v${e.version}`:"version loading";return i.jsxs("p",{className:"flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-slate-300",children:[i.jsx("span",{children:"Operational dashboard"}),i.jsx("span",{className:"font-mono text-xs text-slate-400",children:t}),e!=null&&e.repository_url?i.jsxs("a",{className:"inline-flex items-center gap-1 text-xs font-semibold text-slate-200 hover:underline",href:Ze(e.repository_url),rel:"noreferrer",target:"_blank",children:[i.jsx(Gt,{className:"h-3.5 w-3.5","aria-hidden":!0}),"GitHub"]}):null]})}function qf({state:e,isAdmin:t,runningAction:n=null,actionError:r="",onRefresh:s,onApply:a,onCompletePending:o}){var j,b,S,_,N,q,k,B,M,v,F;if(!e)return null;const l=(b=(j=e==null?void 0:e.target)==null?void 0:j.tag_name)==null?void 0:b.trim();if(!t||!l||(e==null?void 0:e.decision)==="noop")return null;const u=Bf(e.decision),c=((S=e.queue)==null?void 0:S.active_total)??0,d=Uf((_=e.classification)==null?void 0:_.risk),h=$f((N=e.target)==null?void 0:N.body),m=((k=(q=e.classification)==null?void 0:q.migration_files)==null?void 0:k.length)??0,p=((M=(B=e.classification)==null?void 0:B.risky_files)==null?void 0:M.length)??0,y=!!(e.executor_reload_pending&&e.dashboard_applied_at&&o),w=!!(a&&m===0);return i.jsxs("section",{className:"rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-950 shadow-sm","aria-label":"Update available",children:[i.jsxs("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[i.jsx(zr,{className:"h-4 w-4 text-amber-700","aria-hidden":!0}),i.jsx("h2",{className:"text-sm font-semibold",children:"Update available"}),i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-1.5 py-0.5 font-mono text-[11px] text-amber-800",children:l}),(v=e.target)!=null&&v.url?i.jsxs("a",{className:"inline-flex items-center gap-1 text-xs font-semibold text-amber-800 hover:underline",href:Ze(e.target.url),rel:"noreferrer",target:"_blank",children:[i.jsx(Gt,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Release"]}):null]}),i.jsxs("p",{className:"mt-1 text-sm text-amber-900",children:[u,e.installed_tag?i.jsxs("span",{className:"font-mono",children:[" from ",e.installed_tag]}):null]}),i.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[s?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-amber-300 bg-white px-2.5 text-xs font-semibold text-amber-900 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:s,children:[i.jsx(ur,{className:V("h-3.5 w-3.5",n==="refresh"&&"animate-spin"),"aria-hidden":!0}),n==="refresh"?"Checking...":"Check now"]}):null,w?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md bg-amber-800 px-2.5 text-xs font-semibold text-white hover:bg-amber-900 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:()=>{window.confirm(`Apply ${l}? This can restart bridge services according to the recorded safe plan.`)&&(a==null||a())},children:[i.jsx(wn,{className:"h-3.5 w-3.5","aria-hidden":!0}),n==="apply"?"Applying...":"Apply update"]}):null,y?i.jsxs("button",{className:"inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-amber-300 bg-white px-2.5 text-xs font-semibold text-amber-900 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:n!==null,onClick:o,children:[i.jsx(Gn,{className:"h-3.5 w-3.5","aria-hidden":!0}),n==="complete"?"Completing...":"Complete reload"]}):null]})]}),i.jsxs("div",{className:"grid gap-2 text-xs sm:grid-cols-3 lg:min-w-[420px]",children:[i.jsx(ai,{label:"Impact",value:d}),i.jsx(ai,{label:"Active jobs",value:String(c)}),i.jsx(ai,{label:"Admin only",value:"autoupdate"})]})]}),e.blocked_reason||e.executor_reload_pending||m>0||p>0?i.jsxs("div",{className:"mt-3 flex flex-wrap gap-2 text-xs",children:[e.executor_reload_pending?i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1 font-semibold",children:"executor reload pending"}):null,e.blocked_reason?i.jsx("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1 font-mono",children:e.blocked_reason}):null,m>0?i.jsxs("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1",children:[m," migration file",m===1?"":"s"]}):null,p>0?i.jsxs("span",{className:"rounded-sm border border-amber-300 bg-white px-2 py-1",children:[p," executor/shared file",p===1?"":"s"]}):null]}):null,h?i.jsxs("div",{className:"mt-3 rounded-md border border-amber-200 bg-white/70 p-2.5",children:[i.jsx("div",{className:"text-[11px] font-semibold uppercase text-amber-800",children:"Changelog preview"}),i.jsx(Hf,{markdown:h})]}):null,(F=e.warnings)!=null&&F.length?i.jsx("div",{className:"mt-2 font-mono text-xs text-amber-800",children:e.warnings[0]}):null,r?i.jsxs("div",{className:"mt-2 rounded-sm border border-amber-300 bg-white px-2 py-1 font-mono text-xs text-amber-900",children:["Action failed: ",r]}):null]})}function ai({label:e,value:t}){return i.jsxs("div",{className:"min-w-0 rounded-md border border-amber-200 bg-white/80 px-2 py-1.5",children:[i.jsx("div",{className:"text-[11px] font-semibold uppercase text-amber-700",children:e}),i.jsx("div",{className:"mt-0.5 truncate font-mono text-xs text-amber-950",children:t})]})}function Bf(e){return{stage_dashboard_reload:"Dashboard reload can be staged now",stage_defer_executor_reload:"Dashboard reload can be staged; executor reload waits for the queue",stage_full_reload:"Full reload can be staged now",defer_migration:"Migration release is waiting for a quiet queue"}[e??""]??"Update plan recorded"}function Uf(e){return{dashboard_only:"dashboard only",executor_or_queue:"executor or queue",executor_or_shared:"executor or shared",migration_required:"migration",none:"none"}[e??""]??"unknown"}function $f(e){return(e??"").trim()}function Hf({markdown:e}){return i.jsx("div",{className:"mt-1 text-sm leading-relaxed text-amber-950",children:i.jsx(Nm,{allowedElements:["a","blockquote","code","em","h1","h2","h3","h4","li","ol","p","strong","ul"],components:{a:({href:t,children:n})=>i.jsx("a",{className:"font-semibold text-amber-800 underline underline-offset-2",href:Ze(t??""),rel:"noreferrer",target:"_blank",children:n}),blockquote:({children:t})=>i.jsx("blockquote",{className:"mt-2 border-l-2 border-amber-300 pl-2 text-amber-900",children:t}),code:({children:t})=>i.jsx("code",{className:"rounded-sm bg-amber-100 px-1 py-0.5 font-mono text-[0.85em] text-amber-950",children:t}),h1:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h2:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h3:({children:t})=>i.jsx("h3",{className:"mt-2 text-sm font-semibold text-amber-950 first:mt-0",children:t}),h4:({children:t})=>i.jsx("h4",{className:"mt-2 text-xs font-semibold uppercase text-amber-800 first:mt-0",children:t}),li:({children:t})=>i.jsx("li",{className:"break-words pl-0.5 [overflow-wrap:anywhere]",children:t}),ol:({children:t})=>i.jsx("ol",{className:"mt-1 list-decimal space-y-1 pl-5 first:mt-0",children:t}),p:({children:t})=>i.jsx("p",{className:"mt-1 break-words [overflow-wrap:anywhere] first:mt-0",children:t}),strong:({children:t})=>i.jsx("strong",{className:"font-semibold",children:t}),em:({children:t})=>i.jsx("em",{className:"italic",children:t}),ul:({children:t})=>i.jsx("ul",{className:"mt-1 list-disc space-y-1 pl-5 first:mt-0",children:t})},children:e})})}function Kf({isDashboardRoute:e,isSystemRoute:t=!1,isKnowledgeRoute:n,isMcpRoute:r=!1,isWebhooksRoute:s=!1,showWebhooks:a=!1,knowledgeBadgeCount:o=0,onNavigate:l}){return i.jsxs("nav",{className:"flex min-w-0 rounded-lg border border-border bg-panel p-1 shadow-sm","aria-label":"Dashboard sections",children:[i.jsxs(Dn,{href:"/",active:e,onNavigate:l,children:[i.jsx(Qo,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Jobs"})]}),i.jsxs(Dn,{href:"/system",active:t,onNavigate:l,children:[i.jsx(nc,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"System"})]}),a?i.jsxs(Dn,{href:"/webhooks",active:s,onNavigate:l,children:[i.jsx(bn,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Webhooks"})]}):null,i.jsxs(Dn,{href:"/knowledge",active:n,onNavigate:l,children:[i.jsx(Hi,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"Knowledge"}),o>0?i.jsx("span",{className:V("inline-flex h-5 min-w-5 items-center justify-center rounded-full border px-1 font-mono text-[11px] leading-none",n?"border-white/40 bg-white/15 text-white":"border-amber-200 bg-amber-100 text-amber-800"),"aria-label":`${o} proposed knowledge ${o===1?"item":"items"}`,children:o}):null]}),i.jsxs(Dn,{href:"/mcp",active:r,onNavigate:l,children:[i.jsx(Tr,{className:"h-4 w-4","aria-hidden":!0}),i.jsx("span",{children:"MCP"})]})]})}function qn({text:e}){return i.jsxs("div",{className:"flex items-center justify-center gap-2 py-10 text-sm text-muted",children:[i.jsx(ur,{className:"h-4 w-4 animate-spin","aria-hidden":!0}),e]})}function Qf({summary:e,timeseries:t,exceptions:n,hooks:r,deliveries:s,section:a,summaryLoading:o,sectionLoading:l,loadingMore:u,hasMore:c,deliveryFilters:d,error:h,onSectionChange:m,onLoadMore:p,onDeliveryFiltersChange:y,onViewHook:w,onRefresh:j}){var _,N,q,k,B,M;const b=Object.values((e==null?void 0:e.receipts)??{}).reduce((v,F)=>v+F,0),S=[{id:"overview",label:"Overview"},{id:"hooks",label:"Hooks",count:(_=e==null?void 0:e.totals)==null?void 0:_.hooks},{id:"deliveries",label:"Deliveries",count:(N=e==null?void 0:e.totals)==null?void 0:N.deliveries}];return i.jsxs("section",{className:"grid gap-4",children:[i.jsx(zl,{icon:i.jsx(bn,{className:"h-5 w-5 text-muted","aria-hidden":!0}),title:"GitHub webhooks",subtitle:(e==null?void 0:e.mode)==="primary"?"Primary webhook ingestion. IMAP remains active as an idempotent safety net.":(e==null?void 0:e.mode)==="canary"?"Canary ingestion health. Only enabled repositories may create jobs.":"Shadow ingestion health. Deliveries are observed but do not create jobs.",action:i.jsx(lt,{onClick:j})}),h?i.jsx(Ne,{tone:"error",text:h.message}):null,i.jsx("div",{className:"flex max-w-full flex-wrap rounded-md border border-border bg-white p-1",role:"tablist","aria-label":"Webhook dashboard section",children:S.map(v=>i.jsxs("button",{type:"button",role:"tab","aria-label":v.count===void 0?v.label:`${v.label} (${v.count} total)`,"aria-selected":a===v.id,className:V("inline-flex h-8 items-center gap-2 rounded px-3 text-sm font-semibold",a===v.id?"bg-primary text-white":"text-muted hover:bg-slate-50 hover:text-foreground"),onClick:()=>m(v.id),children:[v.label,v.count!==void 0?i.jsx("span",{className:"rounded border border-current/30 px-1 font-mono text-[10px]",children:v.count}):null]},v.id))}),i.jsxs("div",{className:"grid grid-cols-2 gap-3 xl:grid-cols-4","aria-label":"Webhook status",children:[i.jsx(_e,{title:"Receipts",value:b,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Duplicates",value:(e==null?void 0:e.duplicate_deliveries)??0,icon:i.jsx(ur,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Cross-source matches",value:(e==null?void 0:e.cross_source_matches)??0,icon:i.jsx(vn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Mode",value:o?"…":(e==null?void 0:e.mode)??"unknown",icon:i.jsx(Ho,{className:"h-5 w-5"})})]}),a==="overview"?i.jsxs(i.Fragment,{children:[i.jsx(fe,{title:"Delivery activity",children:l?i.jsx(qn,{text:"Loading delivery activity…"}):t!=null&&t.length?i.jsx("div",{className:"h-72","aria-label":"Webhook deliveries over time",children:i.jsx(rr,{width:"100%",height:"100%",children:i.jsxs(Fr,{data:t,children:[i.jsx(ir,{strokeDasharray:"3 3"}),i.jsx(sr,{dataKey:"bucket"}),i.jsx(ar,{allowDecimals:!1}),i.jsx(or,{}),i.jsx(ko,{}),i.jsx(Vt,{dataKey:"observed",stackId:"deliveries",fill:"#2563eb"}),i.jsx(Vt,{dataKey:"duplicate",stackId:"deliveries",fill:"#f59e0b"}),i.jsx(Vt,{dataKey:"unsupported",stackId:"deliveries",fill:"#94a3b8"})]})})}):i.jsx(Z,{text:"No webhook activity in the selected 30-day window."})}),i.jsx(fe,{title:"Receipt states",children:o?i.jsx(qn,{text:"Loading webhook summary…"}):Object.keys((e==null?void 0:e.receipts)??{}).length?i.jsx("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:Object.entries((e==null?void 0:e.receipts)??{}).sort(([v],[F])=>v.localeCompare(F)).map(([v,F])=>i.jsx(J,{label:v,value:F},v))}):i.jsx(Z,{text:"No webhook deliveries observed yet."})}),i.jsx(fe,{title:"Cross-source coverage",children:i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-4",children:[i.jsx(J,{label:"Both sources",value:((q=e==null?void 0:e.coverage)==null?void 0:q.both)??0}),i.jsx(J,{label:"IMAP only",value:((k=e==null?void 0:e.coverage)==null?void 0:k.imap_only)??0}),i.jsx(J,{label:"Webhook only",value:((B=e==null?void 0:e.coverage)==null?void 0:B.webhook_only)??0}),i.jsx(J,{label:"Coverage",value:((M=e==null?void 0:e.coverage)==null?void 0:M.ratio)==null?"not measurable":`${Math.round(e.coverage.ratio*100)}%`})]})}),i.jsx(fe,{title:"Exceptions requiring review",children:n!=null&&n.length?i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full min-w-[720px] text-left text-sm",children:[i.jsx("thead",{className:"border-b border-border text-xs text-muted",children:i.jsxs("tr",{children:[i.jsx("th",{className:"px-3 py-2",children:"Type"}),i.jsx("th",{className:"px-3 py-2",children:"Repository"}),i.jsx("th",{className:"px-3 py-2",children:"Reference"}),i.jsx("th",{className:"px-3 py-2",children:"Observed"})]})}),i.jsx("tbody",{children:n.map(v=>i.jsxs("tr",{className:"border-b border-border/70 last:border-0",children:[i.jsx("td",{className:"px-3 py-2 font-semibold",children:v.kind}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs",children:v.repository??"unknown"}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs",children:v.event_key??v.reference}),i.jsx("td",{className:"px-3 py-2 font-mono text-xs text-muted",children:v.created_at})]},`${v.kind}:${v.reference}`))})]})}):i.jsx(Z,{text:"No cross-source exceptions in retained data."})})]}):null,a==="hooks"?i.jsx(fe,{title:"Hook inventory",children:l?i.jsx(qn,{text:"Loading hook inventory…"}):r!=null&&r.length?i.jsx(Di,{noun:"hooks",hasMore:c,loading:u,onLoadMore:p,children:i.jsxs("table",{className:"w-full min-w-[920px] text-left text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"sticky top-0 z-10 border-b border-border bg-panel text-left text-xs text-muted",children:[i.jsx("th",{className:"px-3 py-2",children:"Target"}),i.jsx("th",{className:"px-3 py-2",children:"State"}),i.jsx("th",{className:"px-3 py-2",children:"Configuration"}),i.jsx("th",{className:"px-3 py-2",children:"Last delivery"}),i.jsx("th",{className:"px-3 py-2",children:"Last ping"})]})}),i.jsx("tbody",{children:r.map(v=>i.jsxs("tr",{className:"cursor-pointer border-b border-border/70 last:border-0 hover:bg-slate-50",onClick:()=>w(v.id),children:[i.jsxs("td",{className:"px-3 py-3",children:[i.jsx("button",{type:"button",className:"text-left font-semibold text-primary hover:underline",onClick:F=>{F.stopPropagation(),w(v.id)},children:v.target}),i.jsxs("div",{className:"font-mono text-xs text-muted",children:[v.target_type," · #",v.id]})]}),i.jsx("td",{className:"px-3 py-3",children:i.jsx("span",{className:V("rounded border px-2 py-1 text-xs font-semibold",v.status==="receiving"?"border-emerald-200 bg-emerald-50 text-emerald-700":v.status==="inactive"?"border-red-200 bg-red-50 text-red-700":"border-slate-200 bg-slate-50 text-slate-600"),children:v.status})}),i.jsxs("td",{className:"max-w-sm px-3 py-3 text-xs",children:[i.jsx("div",{children:v.events.join(", ")||"No event snapshot"}),i.jsxs("div",{className:"mt-1 font-mono text-muted",children:[v.content_type??"content type unknown"," · SSL ",v.ssl_verify===null||v.ssl_verify===void 0?"unknown":v.ssl_verify?"verified":"disabled"]})]}),i.jsxs("td",{className:"px-3 py-3 text-xs",children:[i.jsxs("div",{className:"font-semibold",children:[v.last_event_name??"Never",v.last_action?` · ${v.last_action}`:""]}),i.jsx("div",{className:"mt-1 font-mono text-muted",children:v.last_repository??v.last_event_at??"No delivery observed"})]}),i.jsx("td",{className:"px-3 py-3 font-mono text-xs text-muted",children:v.last_ping_at??"Never"})]},v.id))})]})}):i.jsx(Z,{text:"No hook inventory is available. Redeliver a signed ping from GitHub to create the sanitized configuration snapshot."})}):null,a==="deliveries"?i.jsxs(fe,{title:"Recent deliveries",children:[i.jsx(Vf,{filters:d,onChange:y}),l?i.jsx(qn,{text:"Loading deliveries…"}):s!=null&&s.length?i.jsx(Di,{noun:"deliveries",hasMore:c,loading:u,onLoadMore:p,children:i.jsx(Fl,{deliveries:s,onViewHook:w})}):i.jsx(Z,{text:"No deliveries match the current filters."})]}):null]})}function Vf({filters:e,onChange:t}){const n=[{key:"hook_id",label:"Hook ID",placeholder:"690954530"},{key:"event_name",label:"Event",placeholder:"issue_comment"},{key:"repository",label:"Repository",placeholder:"gisce/repository"},{key:"result",label:"Result",placeholder:"observed"}];return i.jsx("div",{className:"grid gap-2 border-b border-border p-3 sm:grid-cols-2 xl:grid-cols-4",children:n.map(r=>i.jsxs("label",{className:"grid gap-1 text-xs font-semibold text-muted",children:[r.label,i.jsx("input",{className:"h-9 rounded-md border border-border bg-white px-2 font-mono text-xs text-foreground",value:e[r.key],placeholder:r.placeholder,onChange:s=>t({...e,[r.key]:s.target.value})})]},r.key))})}function Fl({deliveries:e,onViewHook:t}){return i.jsxs("table",{className:"w-full min-w-[980px] text-left text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"sticky top-0 z-10 border-b border-border bg-panel text-left text-xs text-muted",children:[i.jsx("th",{className:"px-3 py-2",children:"Received"}),i.jsx("th",{className:"px-3 py-2",children:"Hook"}),i.jsx("th",{className:"px-3 py-2",children:"Event"}),i.jsx("th",{className:"px-3 py-2",children:"Repository"}),i.jsx("th",{className:"px-3 py-2",children:"Result"}),i.jsx("th",{className:"px-3 py-2",children:"Delivery"})]})}),i.jsx("tbody",{children:e.map(n=>{var r;return i.jsxs("tr",{className:"border-b border-border/70 last:border-0",children:[i.jsx("td",{className:"px-3 py-3 font-mono text-xs text-muted",children:n.created_at}),i.jsx("td",{className:"px-3 py-3",children:n.hook_id?i.jsxs("button",{type:"button",className:"text-left text-primary hover:underline",onClick:()=>t(n.hook_id),children:[i.jsx("span",{className:"block font-semibold",children:((r=n.hook)==null?void 0:r.target)??`Hook #${n.hook_id}`}),i.jsxs("span",{className:"font-mono text-xs",children:["#",n.hook_id]})]}):i.jsx("span",{className:"text-xs text-muted",children:"Unknown (legacy)"})}),i.jsxs("td",{className:"px-3 py-3 font-semibold",children:[n.event_name,n.action?` · ${n.action}`:""]}),i.jsx("td",{className:"px-3 py-3",children:n.repository??"—"}),i.jsxs("td",{className:"px-3 py-3",children:[i.jsx("span",{className:"rounded border border-border bg-slate-50 px-2 py-1 text-xs font-semibold",children:n.status}),n.duplicate_count?i.jsxs("span",{className:"ml-2 font-mono text-xs text-muted",children:[n.duplicate_count," retries"]}):null]}),i.jsx("td",{className:"max-w-[14rem] truncate px-3 py-3 font-mono text-xs text-muted",title:n.delivery_id,children:n.delivery_id})]},n.delivery_id)})})]})}function Di({noun:e,hasMore:t,loading:n,onLoadMore:r,children:s,className:a}){return i.jsxs("div",{"data-testid":`lazy-scroll-${e}`,className:V("max-h-[640px] overflow-auto rounded-md border border-border",a),children:[s,i.jsx(Wf,{noun:e,hasMore:t,loading:n,onLoadMore:r})]})}function Wf({noun:e,hasMore:t,loading:n,onLoadMore:r}){const s=T.useRef(null),a=T.useRef(!1);return T.useEffect(()=>{n||(a.current=!1)},[n]),T.useEffect(()=>{const o=s.current;if(!o||!t||n||!r)return;const l=()=>{a.current||(a.current=!0,r())};if(!("IntersectionObserver"in window)){l();return}const u=new IntersectionObserver(c=>{c.some(d=>d.isIntersecting)&&l()},{rootMargin:"240px 0px"});return u.observe(o),()=>u.disconnect()},[t,n,e,r]),!t&&!n?null:i.jsx("div",{ref:s,className:"flex min-h-10 items-center justify-center border-t border-border px-3 py-2 text-xs font-medium text-muted","aria-live":"polite",children:n?`Loading more ${e}...`:`Scroll for more ${e}`})}function Gf({data:e,loading:t,error:n,onBack:r,onRefresh:s,onViewHook:a}){if(t)return i.jsx(qn,{text:"Loading hook detail…"});if(n)return i.jsxs("div",{className:"grid gap-3",children:[i.jsx(Ne,{tone:"error",text:n.message}),i.jsx("button",{type:"button",className:"w-fit rounded border border-border px-3 py-2 text-sm font-semibold",onClick:r,children:"Back to hooks"})]});if(!e)return i.jsx(Z,{text:"Hook detail is not available."});const o=e.hook;return i.jsxs("section",{className:"grid gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsxs("div",{children:[i.jsxs("button",{type:"button",className:"mb-2 inline-flex items-center gap-2 text-sm font-semibold text-primary hover:underline",onClick:r,children:[i.jsx(Bo,{className:"h-4 w-4","aria-hidden":!0}),"Back to hooks"]}),i.jsx("h2",{className:"text-xl font-semibold",children:o.target}),i.jsxs("p",{className:"font-mono text-xs text-muted",children:[o.target_type," webhook #",o.id]})]}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx(lt,{onClick:s}),o.admin_url?i.jsxs("a",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold hover:bg-slate-50",href:Ze(o.admin_url),target:"_blank",rel:"noreferrer",children:[i.jsx(Gt,{className:"h-4 w-4","aria-hidden":!0}),"Open in GitHub"]}):null]})]}),i.jsxs("div",{className:"grid grid-cols-2 gap-3 lg:grid-cols-4",children:[i.jsx(_e,{title:"State",value:o.status,icon:i.jsx(bn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Deliveries",value:e.stats.deliveries,icon:i.jsx(vn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Retries",value:e.stats.duplicates,icon:i.jsx(ur,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Unsupported",value:e.stats.unsupported,icon:i.jsx(zr,{className:"h-5 w-5"})})]}),i.jsxs(fe,{title:"Sanitized configuration",children:[i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[i.jsx(J,{label:"Active",value:o.active?"yes":"no"}),i.jsx(J,{label:"Content type",value:o.content_type??"unknown"}),i.jsx(J,{label:"SSL verification",value:o.ssl_verify===null||o.ssl_verify===void 0?"unknown":o.ssl_verify?"enabled":"disabled"}),i.jsx(J,{label:"Destination URL",value:o.delivery_url??"unknown"}),i.jsx(J,{label:"GitHub created",value:o.github_created_at??"unknown"}),i.jsx(J,{label:"GitHub updated",value:o.github_updated_at??"unknown"}),i.jsx(J,{label:"Last ping",value:o.last_ping_at??"never"}),i.jsx(J,{label:"Last delivery",value:o.last_event_at??"never"}),i.jsx(J,{label:"Last result",value:o.last_result??"unknown"})]}),i.jsxs("div",{className:"mt-3 rounded-md border border-border p-3",children:[i.jsx("div",{className:"text-xs font-semibold text-muted",children:"Subscribed events"}),i.jsx("div",{className:"mt-2 flex flex-wrap gap-1.5",children:o.events.length?o.events.map(l=>i.jsx("span",{className:"rounded border border-border bg-slate-50 px-2 py-1 font-mono text-xs",children:l},l)):i.jsx("span",{className:"text-sm text-muted",children:"No event snapshot; redeliver a ping."})})]})]}),i.jsx(fe,{title:"Latest observed delivery",children:i.jsxs("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[i.jsx(J,{label:"Event",value:o.last_event_name?`${o.last_event_name}${o.last_action?` · ${o.last_action}`:""}`:"none"}),i.jsx(J,{label:"Repository",value:o.last_repository??"none"}),i.jsx(J,{label:"Delivery ID",value:o.last_delivery_id??"none"})]})}),i.jsx(fe,{title:"Recent deliveries",children:e.recent_deliveries.length?i.jsx(Fl,{deliveries:e.recent_deliveries,onViewHook:a}):i.jsx(Z,{text:"This hook has no retained deliveries."})})]})}function Jf({processes:e,processesLoading:t,processesError:n,systemd:r,systemdLoading:s,systemdError:a,alerts:o,alertsLoading:l,alertsError:u,now:c,onRefreshProcesses:d,onRefreshSystemd:h,onRefreshAlerts:m}){return i.jsxs("section",{className:"grid gap-4","aria-label":"Bridge system",children:[i.jsxs(fe,{title:"Systemd",action:i.jsx(lt,{onClick:h}),children:[a?i.jsx(Ne,{tone:"error",text:a.message}):null,i.jsx(Rx,{data:r,loading:s})]}),i.jsxs(fe,{title:"Process activity",action:i.jsx(lt,{onClick:d}),children:[n?i.jsx(Ne,{tone:"error",text:n.message}):null,i.jsx(Ax,{data:e,loading:t})]}),i.jsxs(fe,{title:"Monitor alerts",action:i.jsx(lt,{onClick:m}),children:[u?i.jsx(Ne,{tone:"error",text:u.message}):null,i.jsx(Lx,{alerts:o,loading:l,now:c})]})]})}function Dn({href:e,active:t,children:n,onNavigate:r}){return i.jsx("a",{className:V("inline-flex h-8 min-w-0 flex-1 items-center justify-center gap-1 rounded-md px-1.5 text-xs font-semibold sm:flex-none sm:gap-1.5 sm:px-3 sm:text-sm [&>span]:truncate [&>svg]:shrink-0",t?"bg-primary text-white shadow-sm":"text-muted hover:bg-slate-50 hover:text-foreground"),href:e,onClick:s=>{!r||s.defaultPrevented||s.button!==0||s.metaKey||s.ctrlKey||s.altKey||s.shiftKey||(s.preventDefault(),r(e))},children:n})}function Xf({jobId:e,detail:t,selectedJob:n,user:r,onBackToDashboard:s,onRetry:a,onDismiss:o,onCancel:l,onRefresh:u}){const[c,d]=T.useState(!1),[h,m]=T.useState(!1),[p,y]=T.useState(!1),w=!!(r!=null&&r.is_admin&&n&&zn(n.status)),j=!!(n&&Oi(n,r)),b=c?"Retrying...":"Retry",S=h?"Dismissing...":"Dismiss",_=p?"Cancelling...":"Cancel";return i.jsxs("div",{className:"grid min-w-0 gap-3 sm:gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[i.jsxs("a",{className:"inline-flex h-9 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50",href:"/",onClick:N=>{N.defaultPrevented||N.button!==0||N.metaKey||N.ctrlKey||N.altKey||N.shiftKey||(N.preventDefault(),s())},children:[i.jsx(Bo,{className:"h-4 w-4","aria-hidden":!0}),"Dashboard"]}),i.jsxs("div",{className:"flex items-center gap-2",children:[w?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:c,onClick:async()=>{if(window.confirm(`Retry job #${e}?`)){d(!0);try{await a(e)}finally{d(!1)}}},children:[i.jsx(Gn,{className:"h-4 w-4","aria-hidden":!0}),b]}):null,w?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md border border-border bg-white px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:h,onClick:async()=>{if(window.confirm(`Dismiss job #${e}?`)){m(!0);try{await o(e)}finally{m(!1)}}},children:[i.jsx(wn,{className:"h-4 w-4","aria-hidden":!0}),S]}):null,j?i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 rounded-md border border-red-200 bg-red-50 px-3 text-sm font-semibold text-red-700 hover:bg-red-100 disabled:cursor-not-allowed disabled:opacity-60",type:"button",disabled:p,onClick:async()=>{const N=window.prompt(`Cancel job #${e}? Optional reason:`);if(N!==null){y(!0);try{await l(e,N)}finally{y(!1)}}},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),_]}):null,i.jsx(lt,{onClick:u})]})]}),i.jsx(fe,{title:`Job #${e}`,className:"p-3 sm:p-4",children:t})]})}function Yf({selectedJobId:e,selectedJob:t,loading:n,error:r,session:s,sessionEvents:a,transcript:o,now:l}){return t?i.jsx(kx,{job:t,session:s,sessionEvents:a,transcript:o,now:l}):e!==null&&n?i.jsx(Z,{text:"Loading selected job..."}):e!==null&&r?i.jsx(Ne,{tone:"error",text:`Job #${e}: ${r.message}`}):i.jsx(Z,{text:"Select a job to inspect its timeline, worklog and GitHub links."})}function Zf({data:e,loading:t,error:n,repo:r,status:s,user:a,now:o,onRepoChange:l,onStatusChange:u,onApprove:c,onReject:d,onUpdateRuleScope:h,onDeleteRule:m,onRefresh:p}){const y=(e==null?void 0:e.summary)??{},[w,j]=T.useState("proposals"),b=[{id:"proposals",label:"Proposals",count:(e==null?void 0:e.proposals.length)??0},{id:"rules",label:"Rules",count:(e==null?void 0:e.rules.length)??0},{id:"events",label:"Events",count:(e==null?void 0:e.events.length)??0}];return i.jsxs("div",{className:"grid min-w-0 gap-4",children:[i.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsxs("h2",{className:"flex items-center gap-2 text-base font-semibold",children:[i.jsx(Hi,{className:"h-5 w-5 text-muted","aria-hidden":!0}),"Acquired knowledge"]}),i.jsx("p",{className:"text-xs text-muted",children:"Captured feedback, proposed rules and curated agent memory."})]}),i.jsx(lt,{onClick:p})]}),n?i.jsx(Ne,{tone:"error",text:n.message}):null,i.jsxs("section",{className:"grid grid-cols-2 gap-3 lg:grid-cols-4","aria-label":"Knowledge metrics",children:[i.jsx(_e,{title:"Proposed",value:y.proposed??0,icon:i.jsx($o,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Approved",value:y.approved??0,icon:i.jsx(wn,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Rules",value:y.rules??0,icon:i.jsx(Ko,{className:"h-5 w-5"})}),i.jsx(_e,{title:"Events",value:y.events??0,icon:i.jsx(bn,{className:"h-5 w-5"})})]}),i.jsx(fe,{title:"Filters",className:"p-3",children:i.jsxs("div",{className:V("grid gap-3",w==="proposals"?"md:grid-cols-[minmax(0,1fr)_220px]":"md:grid-cols-[minmax(0,1fr)]"),children:[i.jsx(Ye,{label:"Repository",children:i.jsxs("select",{className:"control",value:r,onChange:S=>l(S.target.value),children:[i.jsx("option",{value:"",children:"All repositories"}),((e==null?void 0:e.repositories)??[]).map(S=>i.jsx("option",{value:S,children:S},S))]})}),w==="proposals"?i.jsx(Ye,{label:"Proposal status",children:i.jsxs("select",{className:"control",value:s,onChange:S=>u(S.target.value),children:[i.jsx("option",{value:"",children:"All statuses"}),i.jsx("option",{value:"proposed",children:"proposed"}),i.jsx("option",{value:"approved",children:"approved"}),i.jsx("option",{value:"rejected",children:"rejected"}),i.jsx("option",{value:"error",children:"error"})]})}):null]})}),i.jsxs(fe,{title:"Knowledge records",action:i.jsx("div",{className:"flex max-w-full flex-wrap rounded-md border border-border bg-white p-0.5",role:"tablist","aria-label":"Knowledge record type",children:b.map(S=>i.jsxs("button",{className:V("inline-flex h-8 items-center gap-1.5 rounded px-2.5 text-xs font-semibold",w===S.id?"bg-primary text-white":"text-muted hover:bg-slate-50 hover:text-foreground"),type:"button",role:"tab","aria-label":`${S.label} (${S.count})`,"aria-selected":w===S.id,onClick:()=>j(S.id),children:[i.jsx("span",{children:S.label}),i.jsx("span",{className:V("rounded-sm border px-1 font-mono text-[10px]",w===S.id?"border-white/40 text-white":"border-border text-muted"),children:S.count})]},S.id))}),children:[w==="proposals"?i.jsx(ex,{proposals:(e==null?void 0:e.proposals)??[],loading:t,isAdmin:!!(a!=null&&a.is_admin),now:o,onApprove:c,onReject:d}):null,w==="rules"?i.jsx(rx,{rules:(e==null?void 0:e.rules)??[],loading:t,now:o,onUpdateRuleScope:h,onDeleteRule:m}):null,w==="events"?i.jsx(ix,{events:(e==null?void 0:e.events)??[],loading:t,now:o}):null]})]})}function ex({proposals:e,loading:t,isAdmin:n,now:r,onApprove:s,onReject:a}){const[o,l]=T.useState(null);return t&&e.length===0?i.jsx(Z,{text:"Loading proposals..."}):e.length===0?i.jsx(Z,{text:"No proposals match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(u=>i.jsxs("article",{className:"grid min-w-0 gap-2 rounded-md border border-border bg-white p-3",children:[i.jsx(Bl,{scope:u.scope,type:u.type,confidence:u.confidence,status:u.status,timestamp:u.updated_at,now:r}),i.jsx("p",{className:"min-w-0 break-words text-sm font-medium [overflow-wrap:anywhere]",children:u.rule||u.reason||"No reusable rule proposed."}),u.reason?i.jsx("p",{className:"min-w-0 break-words text-xs text-muted [overflow-wrap:anywhere]",children:u.reason}):null,u.source_event?i.jsx(tx,{event:u.source_event}):i.jsxs("p",{className:"font-mono text-xs text-muted",children:["Source event ",u.event_id]}),u.error?i.jsx(Ne,{tone:"error",text:u.error}):null,n&&u.status==="proposed"?i.jsxs("div",{className:"flex flex-wrap gap-2",children:[i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:opacity-60",type:"button",disabled:o===u.id,onClick:async()=>{l(u.id);try{await s(u.id)}finally{l(null)}},children:[i.jsx(wn,{className:"h-4 w-4","aria-hidden":!0}),"Approve"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:o===u.id,onClick:async()=>{l(u.id);try{await a(u.id)}finally{l(null)}},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Reject"]})]}):null]},u.id))})}function tx({event:e}){const t=e.trigger_actor||(e.actor!=="github"?e.actor:null);return i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-border bg-slate-50 px-2 py-1.5",children:[i.jsx(Cn,{actor:t,avatarUrl:e.trigger_actor_avatar_url,framed:!0}),e.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border bg-white px-2 text-xs font-semibold text-foreground hover:bg-slate-50",href:Sn(e.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",e.source_job_id]}):null,e.github_urls.length>0?i.jsx(Xn,{urls:e.github_urls,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]})}function nx(e){const t=[{value:"global",label:"global"}];if(e.startsWith("repo:")){const n=e.slice(5),[r,s]=n.split("/",2);r&&s&&(t.push({value:`org:${r}`,label:`org:${r}`}),t.push({value:`repo:${r}/${s}`,label:`repo:${r}/${s}`}))}else e.startsWith("org:")&&t.push({value:e,label:e});return t.some(n=>n.value===e)||t.push({value:e,label:e}),t}function rx({rules:e,loading:t,now:n,onUpdateRuleScope:r,onDeleteRule:s}){const[a,o]=T.useState(null),[l,u]=T.useState(null),[c,d]=T.useState("");return t&&e.length===0?i.jsx(Z,{text:"Loading curated rules..."}):e.length===0?i.jsx(Z,{text:"No curated rules match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(h=>{const m=h.source_event_details??[],p=m[0],y=p?p.trigger_actor||(p.actor!=="github"?p.actor:null):null,w=m.flatMap(N=>N.github_urls??[]),j=nx(h.scope),b=l===h.id,S=a===h.id,_=!!h.can_manage;return i.jsxs("article",{className:"grid min-w-0 gap-2 rounded-md border border-border bg-white p-3",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsx(Bl,{scope:h.scope,type:h.type,confidence:h.confidence,status:`${h.observations} observation${h.observations===1?"":"s"}`,timestamp:h.last_seen,now:n}),_?i.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[b?i.jsxs(i.Fragment,{children:[i.jsx(Ye,{label:"Scope",children:i.jsx("select",{className:"control h-8 min-w-[180px] py-1 text-xs",value:c,disabled:S,onChange:N=>d(N.target.value),children:j.map(N=>i.jsx("option",{value:N.value,children:N.label},N.value))})}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S||c===h.scope,title:"Save scope",onClick:async()=>{if(c!==h.scope){o(h.id);try{await r(h.id,c),u(null)}finally{o(null)}}},children:[i.jsx(ic,{className:"h-4 w-4","aria-hidden":!0}),"Save"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-muted hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S,title:"Cancel scope edit",onClick:()=>{u(null),d("")},children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Cancel"]})]}):i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-border px-3 text-sm font-semibold text-foreground hover:bg-slate-50 disabled:opacity-60",type:"button",disabled:S,title:"Edit scope",onClick:()=>{u(h.id),d(h.scope)},children:[i.jsx(rc,{className:"h-4 w-4","aria-hidden":!0}),"Edit"]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-red-200 px-3 text-sm font-semibold text-red-700 hover:bg-red-50 disabled:opacity-60",type:"button",disabled:S,onClick:async()=>{if(window.confirm("Delete this curated rule?")){o(h.id);try{await s(h.id)}finally{o(null)}}},children:[i.jsx(ki,{className:"h-4 w-4","aria-hidden":!0}),"Delete"]})]}):null]}),i.jsx("p",{className:"min-w-0 break-words text-sm font-medium [overflow-wrap:anywhere]",children:h.rule}),i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[i.jsx(Cn,{actor:y,avatarUrl:p==null?void 0:p.trigger_actor_avatar_url,framed:!0}),p!=null&&p.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border px-2 text-xs font-semibold text-foreground hover:bg-white",href:Sn(p.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",p.source_job_id]}):null,w.length>0?i.jsx(Xn,{urls:w,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]})]},h.id)})})}function ix({events:e,loading:t,now:n}){return t&&e.length===0?i.jsx(Z,{text:"Loading captured events..."}):e.length===0?i.jsx(Z,{text:"No captured feedback events match the current filters."}):i.jsx("div",{className:"grid gap-2",children:e.map(r=>{const s=r.trigger_actor||(r.actor!=="github"?r.actor:null);return i.jsxs("details",{className:"group rounded-md border border-border bg-white",children:[i.jsxs("summary",{className:"grid cursor-pointer list-none gap-2 px-3 py-2 marker:hidden hover:bg-slate-50",children:[i.jsxs("div",{className:"flex min-w-0 items-center justify-between gap-2",children:[i.jsxs("span",{className:"inline-flex min-w-0 items-center gap-2 font-mono text-xs font-semibold text-muted",children:[i.jsx(yn,{className:"h-3.5 w-3.5 shrink-0 transition-transform group-open:rotate-180","aria-hidden":!0}),i.jsx("span",{className:"truncate",children:Dl(r.scope)})]}),i.jsx("span",{className:"shrink-0 font-mono text-xs text-muted",children:i.jsx(Ie,{value:r.occurred_at,relative:!0,now:n})})]}),i.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[i.jsx(Cn,{actor:s,avatarUrl:r.trigger_actor_avatar_url,framed:!0}),r.source_job_id?i.jsxs("a",{className:"inline-flex h-7 items-center gap-1 rounded-md border border-border px-2 text-xs font-semibold text-foreground hover:bg-white",href:Sn(r.source_job_id),children:[i.jsx(vn,{className:"h-3.5 w-3.5","aria-hidden":!0}),"Job #",r.source_job_id]}):null,r.github_urls.length>0?i.jsx(Xn,{urls:r.github_urls,compact:!0}):i.jsx("span",{className:"font-mono text-xs text-muted",children:"No GitHub link"})]}),i.jsx("p",{className:"line-clamp-2 break-words text-sm [overflow-wrap:anywhere]",children:r.comment})]}),i.jsxs("div",{className:"grid gap-2 border-t border-border px-3 py-2",children:[i.jsxs("div",{children:[i.jsx("h3",{className:"mb-1 text-xs font-semibold text-muted",children:"GitHub links"}),r.github_urls.length>0?i.jsx(Xn,{urls:r.github_urls}):i.jsx("p",{className:"text-xs text-muted",children:"No links recorded."})]}),i.jsx("pre",{className:"max-h-72 overflow-auto rounded-md bg-slate-950 px-3 py-2 font-mono text-xs leading-relaxed text-slate-100",children:JSON.stringify(r.context,null,2)})]})]},r.id)})})}function sx({tokens:e,loading:t,error:n,user:r,ownerOptions:s,dashboardUrl:a,dashboardUrlSource:o,now:l,onCreate:u,onUpdateOwner:c,onRevoke:d,onRefresh:h}){const[m,p]=T.useState(""),[y,w]=T.useState(""),[j,b]=T.useState(!1),[S,_]=T.useState(null),[N,q]=T.useState(null),[k,B]=T.useState(null),[M,v]=T.useState(""),F=e??[],L=s.find(E=>E.login===y);T.useEffect(()=>{var E;r!=null&&r.is_admin&&(y&&s.some(O=>O.login===y)||w((r==null?void 0:r.login)||((E=s[0])==null?void 0:E.login)||""))},[s,r==null?void 0:r.is_admin,r==null?void 0:r.login,y]);const P=(a||(typeof window>"u"?"":window.location.origin)).replace(/\/$/,""),G=`${P}/mcp`,z=`${P}/api/mcp`;return i.jsxs("div",{className:"grid min-w-0 gap-4",children:[i.jsx(zl,{icon:i.jsx(Tr,{className:"h-5 w-5 text-muted","aria-hidden":!0}),title:"MCP access",subtitle:r!=null&&r.is_admin?"Issue and revoke read-only tokens for any dashboard user.":"Issue and revoke read-only tokens linked to your user.",action:i.jsx(lt,{onClick:h})}),n?i.jsx(Ne,{tone:"error",text:n.message}):null,M?i.jsx(Ne,{tone:"error",text:M}):null,i.jsx(ax,{dashboardUrl:G,endpointUrl:z,dashboardUrlSource:o??"request"}),k?i.jsxs("section",{className:"rounded-md border border-emerald-300 bg-emerald-50 p-3 text-emerald-950","aria-label":"Created MCP token",children:[i.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-sm font-semibold",children:"Token created"}),i.jsx("p",{className:"mt-1 text-xs text-emerald-800",children:"This secret is shown once. Store it in the local agent environment before leaving this page."})]}),i.jsxs("button",{className:"inline-flex h-8 items-center gap-2 rounded-md border border-emerald-300 bg-white px-3 text-sm font-semibold text-emerald-900 hover:bg-emerald-100",type:"button",onClick:()=>B(null),children:[i.jsx(Jt,{className:"h-4 w-4","aria-hidden":!0}),"Hide"]})]}),i.jsx("pre",{className:"mt-3 overflow-auto rounded bg-emerald-950 px-3 py-2 font-mono text-xs text-emerald-50",children:k.token})]}):null,i.jsx(fe,{title:"Create token",children:i.jsxs("form",{className:r!=null&&r.is_admin?"grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(12rem,16rem)_auto]":"grid gap-3 md:grid-cols-[minmax(0,1fr)_auto]",onSubmit:async E=>{E.preventDefault();const O=m.trim();if(O){b(!0),v("");try{const Q=await u(O,r!=null&&r.is_admin?y:void 0);B(Q),p("")}catch(Q){v(Q instanceof Error?Q.message:String(Q))}finally{b(!1)}}},children:[i.jsx(Ye,{label:"Token name",children:i.jsx("input",{className:"control",value:m,placeholder:"local agent",disabled:j,onChange:E=>p(E.target.value)})}),r!=null&&r.is_admin?i.jsxs(Ye,{label:"Owner",children:[i.jsx(ql,{ariaLabel:"Owner",value:y,ownerOptions:s,disabled:j||s.length===0,selectedSuffix:E=>E.login===(r==null?void 0:r.login)?" (you)":"",emptyLabel:"No known users",onChange:w}),L?i.jsxs("span",{className:"font-normal text-muted",children:["Token will be linked to @",L.login,"."]}):null]}):null,i.jsxs("button",{className:"inline-flex h-9 items-center justify-center gap-2 self-end rounded-md bg-primary px-3 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60",type:"submit",disabled:j||!m.trim()||!!(r!=null&&r.is_admin&&!y),children:[i.jsx(Tr,{className:"h-4 w-4","aria-hidden":!0}),j?"Creating...":"Create token"]})]})}),i.jsx(fe,{title:"Active tokens",children:i.jsx(ox,{tokens:F,loading:t,now:l,ownerOptions:s,canManageOwners:!!(r!=null&&r.is_admin),revokingId:S,updatingOwnerId:N,onUpdateOwner:async(E,O)=>{q(E),v("");try{await c(E,O)}catch(Q){v(Q instanceof Error?Q.message:String(Q))}finally{q(null)}},onRevoke:async E=>{if(window.confirm("Revoke this MCP token?")){_(E),v("");try{await d(E)}catch(O){v(O instanceof Error?O.message:String(O))}finally{_(null)}}}})})]})}function ax({dashboardUrl:e,endpointUrl:t,dashboardUrlSource:n}){const r=n==="configured"?"Configured public URL":n==="forwarded"?"Forwarded public URL":"Needs public URL",s=n==="request",a=s?"Set GITHUB_AGENT_BRIDGE_DASHBOARD_PUBLIC_URL or forward X-Forwarded-* headers":e,o=s?"Public dashboard URL required before connecting remote agents":t,u=`{ "mcpServers": { "github-agent-bridge": { "url": "${s?"https://bridge.example.com/api/mcp":t}", diff --git a/src/github_agent_bridge/dashboard_static/index.html b/src/github_agent_bridge/dashboard_static/index.html index eb99a67..71d99a2 100644 --- a/src/github_agent_bridge/dashboard_static/index.html +++ b/src/github_agent_bridge/dashboard_static/index.html @@ -4,7 +4,7 @@ GitHub Agent Bridge Dashboard - + diff --git a/src/github_agent_bridge/webhook.py b/src/github_agent_bridge/webhook.py index 1a361cb..e7da414 100644 --- a/src/github_agent_bridge/webhook.py +++ b/src/github_agent_bridge/webhook.py @@ -90,6 +90,8 @@ def webhook_notification( if not url.startswith("https://github.com/"): return None body = str(source.get("body") or "") + if event_name == "workflow_run": + body = f"Workflow run {source.get('conclusion') or source.get('status') or action}.\n{body}" sender = payload.get("sender") if isinstance(payload.get("sender"), dict) else {} login = str(sender.get("login") or "GitHub") title = str(subject.get("title") or subject.get("name") or event_name) diff --git a/systemd/env.example b/systemd/env.example index 579e84e..a776090 100644 --- a/systemd/env.example +++ b/systemd/env.example @@ -90,3 +90,6 @@ GITHUB_AGENT_BRIDGE_WEB_PUSH_ICON_URL= # the same policy used by the reader and only enqueues policy.enabledRepos. GITHUB_AGENT_BRIDGE_WEBHOOK_MODE=shadow GITHUB_AGENT_BRIDGE_WEBHOOK_POLICY=%h/.config/github-agent-bridge/policy.json +# Required in addition to WEBHOOK_MODE=primary. This prevents a config typo from +# changing the source of work without an explicit operator decision. +GITHUB_AGENT_BRIDGE_WEBHOOK_PRIMARY_ACK= diff --git a/tests/test_webhook.py b/tests/test_webhook.py index fb37714..3e52b23 100644 --- a/tests/test_webhook.py +++ b/tests/test_webhook.py @@ -172,6 +172,41 @@ def test_webhook_canary_ignores_repo_outside_enabled_repos(tmp_path): assert con.execute("SELECT COUNT(*) FROM jobs").fetchone()[0] == 0 +def test_webhook_primary_requires_explicit_acknowledgement(tmp_path): + try: + DashboardConfig( + db=tmp_path / "bridge.sqlite3", webhook_mode="primary", + webhook_policy=canary_policy(tmp_path), webhook_primary_ack=False, + ) + except ValueError as exc: + assert "PRIMARY_ACK" in str(exc) + else: + raise AssertionError("primary mode must require an explicit acknowledgement") + + +def test_webhook_primary_enqueues_trusted_repo_without_canary_allowlist(tmp_path): + policy = canary_policy(tmp_path) + policy.write_text(json.dumps({ + "trustedOrgs": ["gisce"], "enabledRepos": [], "botLogins": ["giscebot"], + "actions": {"trustedAuto": ["reply_comment"]}, + })) + payload = actionable_issue_comment_payload() + config = DashboardConfig( + db=tmp_path / "bridge.sqlite3", require_auth=False, + webhook_secrets=(SECRET,), webhook_mode="primary", webhook_policy=policy, + webhook_primary_ack=True, + ) + + response = TestClient(create_app(config)).post( + "/api/webhooks/github", content=payload, headers=signed_headers(payload), + ) + + assert response.json()["mode"] == "primary" + assert response.json()["enqueue_status"] == "enqueued" + with sqlite3.connect(config.db) as con: + assert con.execute("SELECT first_source FROM github_events").fetchone()[0] == "webhook" + + def test_webhook_shadow_selects_secret_by_repository_owner(tmp_path): payload = issue_comment_payload() client = TestClient(create_app(DashboardConfig(