🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@codeyam-editor/codeyam-editor

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@codeyam-editor/codeyam-editor - npm Package Compare versions

Comparing version
0.1.0-staging.g25ba0d1
to
0.1.0-staging.g296f8a2
+155
npm/fleet-probe-transport.js
'use strict';
// The fleet dashboard's two LB-path HTTP probe transports, extracted from
// scripts/operator/fleet-dashboard/server.js so their SOCKET LIFETIME is
// testable.
//
// The undici contract, which is the whole reason this module exists: a `fetch`
// response body is a stream that holds its connection open until it is read to
// completion or explicitly cancelled. IGNORING `res.body` is NOT the same as
// releasing it — the socket stays checked out of the agent's pool, and once the
// peer sends FIN it parks in CLOSE-WAIT forever. Node's `http` module is the
// opposite (an unread response pauses the socket, hence the `res.resume(); //
// drain so the socket can close` in server.js's localGetJson), and that
// asymmetry is what got missed when the fetch path was added.
//
// On 2026-08-01 that leaked 10,749 CLOSE-WAIT sockets to the fleet LB
// (8.228.227.92:443) holding 128MB of unread IAP-login HTML in kernel receive
// queues — ~460 sockets/hour, a ~1-day fuse — driving the dashboard cgroup into
// swap-thrash until the node event loop stalled in `D` state and dashboard-bes
// went UNHEALTHY while systemd still reported the unit active.
//
// So: EVERY return path here consumes or cancels the body. `fetch` is injected
// rather than closed over, so a test can drive every branch with a body that
// records whether it was cancelled.
const fpt = require('./fleet-vm-probe-target');
/** Release the connection behind a response we are not going to read.
*
* Swallows its own failure deliberately. `cancel()` rejects when the body was
* already consumed or already errored — in both cases the connection is
* released anyway, so there is nothing to recover from and nothing to report.
* Letting it throw would be actively harmful: these calls sit inside the
* transports' `try`, so a rejection would be caught by the transport's own
* catch and misclassify a perfectly good HTTP response as `unreachable`.
*/
async function disposeBody(res) {
try {
await res.body?.cancel();
} catch {
// Already consumed, already errored, or no body at all — connection is
// released either way.
}
}
/** GET JSON from a resolved LB target.
*
* Uses redirect:'manual' so IAP's 302→accounts.google.com surfaces as a
* classifiable response instead of the fetch silently following it and handing
* us a login page that fails JSON parsing — which would read as "VM is down"
* when the real fault is our token. That 302 carries a full HTML login page,
* which is exactly why the non-ok return below must dispose of the body.
*
* `deps` injects the transport's collaborators for tests: `fetchImpl` (default
* global fetch) and `warn` (default console.warn).
*/
async function lbGetJson(target, timeout, deps = {}) {
const { fetchImpl = globalThis.fetch, warn = console.warn } = deps;
const ctl = new AbortController();
const timer = setTimeout(() => ctl.abort(), timeout);
try {
const res = await fetchImpl(target.url, {
headers: target.headers,
redirect: 'manual',
signal: ctl.signal,
});
const outcome = fpt.classifyProbeResponse({
status: res.status,
location: res.headers.get('location'),
});
if (outcome !== 'ok') {
// 401 and 403 share one outcome but have opposite fixes (OAuth client vs
// IAM grant). Name which one we hit, so the next misconfig is diagnosable
// from the log instead of a live curl against the backend.
const why = fpt.describeAuthMisconfig(res.status);
if (why) warn(`probe ${target.url}: HTTP ${res.status} — ${why}`);
await disposeBody(res);
return { outcome, json: null, status: res.status };
}
// `status` rides on every return so a caller can NAME the HTTP status in a
// fault warning. Without it a reachable-but-unusable body was indiscernible
// from a dead VM in the log — see probeBodyFault.
//
// Both branches below are body-safe without an explicit cancel: `res.text()`
// reads the stream to completion, so the connection is already released by
// the time JSON.parse runs or throws.
try { return { outcome: 'ok', json: JSON.parse(await res.text()), status: res.status }; }
catch { return { outcome: 'unreachable', json: null, error: 'bad-json', status: res.status }; }
} catch (err) {
// No response to dispose of — the request never produced one.
return {
outcome: 'unreachable',
json: null,
error: err && err.name === 'AbortError' ? 'timeout' : 'error',
};
} finally {
clearTimeout(timer);
}
}
/** Reachability-only transport for the PUBLIC preview ingress over the IAP-LB
* seam.
*
* Unlike lbGetJson it does not PARSE a body — the preview root returns HTML, so
* routing it through lbGetJson would fail-close on the non-JSON parse. It must
* still DISPOSE of that body on every path; "does not parse" was historically
* written as "does not touch", and that is precisely what leaked.
*
* Classifies purely on the HTTP response:
* any non-auth HTTP response (200, or even 404/502 — the LB routed to a
* backend that answered) → true (ingress wired);
* auth-misconfigured (302→Google login / 401 / 403) → null (UNKNOWN, never
* false): the preview backend is a SEPARATE IAP backend
* service whose audience/accessor may differ from the
* editor backend the operator token is minted for, so an
* auth challenge here proves nothing about the URL wiring;
* transport error / timeout → false (nothing answered).
*
* Uses redirect:'manual' so an IAP login 302 surfaces as classifiable instead
* of fetch silently following it to a login page.
*/
async function lbProbeReachable(target, timeout, deps = {}) {
const { fetchImpl = globalThis.fetch, warn = console.warn } = deps;
const ctl = new AbortController();
const timer = setTimeout(() => ctl.abort(), timeout);
try {
const res = await fetchImpl(target.url, {
headers: target.headers,
redirect: 'manual',
signal: ctl.signal,
});
const outcome = fpt.classifyProbeResponse({
status: res.status,
location: res.headers.get('location'),
});
if (outcome === 'auth-misconfigured') {
const why = fpt.describeAuthMisconfig(res.status);
if (why) warn(`preview ingress ${target.url}: HTTP ${res.status} — ${why}`);
await disposeBody(res);
return null;
}
await disposeBody(res);
return true;
} catch {
// No response to dispose of — the request never produced one.
return false;
} finally {
clearTimeout(timer);
}
}
module.exports = {
disposeBody,
lbGetJson,
lbProbeReachable,
};
'use strict';
// Pure helpers for the fleet dashboard's DEPLOYED-REVISION staleness signal
// (scripts/operator/fleet-dashboard/server.js requires this; unit tests in
// npm/fleet-revision.test.js).
//
// The dashboard header has always shown the branch name, which says nothing
// about WHICH COMMIT of that branch is serving. On 2026-07-31 the operator
// host's /opt/codeyam-editor sat 104 commits behind origin/editor-improvements-66,
// so the deployed dashboard predated its own memory fix and was
// indistinguishable from one at tip — the third recurrence of a landed fix
// surviving because the served checkout was behind (the June VM-5 slug bug was
// the same shape).
//
// server.js owns the I/O — the bounded `git fetch` / `rev-parse` / `rev-list`
// children and the slow-cycle memo. The two rules that actually matter are here
// and are pure: how a failed check merges over the last good one, and what
// verdict a given count means. Both were previously inline in an async IIFE
// that no test could reach.
/** Merge one revision-check result over the previous memo.
*
* THE RULE: a failed check RETAINS the previous `behind` and records `error` —
* it never reports zero. This is what makes the staleness chip sticky. A
* broken `git fetch` that reset the count to 0 would present a stale dashboard
* as current, which is precisely the failure this whole signal exists to catch;
* degrading to "last known count, plus a note that the check is failing" is
* the honest answer.
*
* A `behind` that is absent, negative, or unparseable counts as no reading and
* falls back to the previous value the same way. `sha` and `branch` likewise
* retain their last known values rather than blanking the header on a hiccup.
*
* A previous `behind` of null (never successfully counted) stays null — it is
* deliberately NOT coerced through Number(), because `Number(null) === 0` is
* the exact coercion that made "no reading" and "zero" indistinguishable in
* readCgroupMemory.
*
* Pure; no I/O. */
function mergeDashboardRevision({ prev, sha, branch, behind, checkedAt, error } = {}) {
const base = (prev && typeof prev === 'object') ? prev : {};
const str = (next, fallback) => ((typeof next === 'string' && next) ? next : (typeof fallback === 'string' && fallback ? fallback : null));
// Strictly a number: a string or null is NOT coerced, so a caller cannot
// accidentally turn "no reading" into 0 the way Number(null) would.
const count = (v) => (typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : null);
const counted = count(behind);
return {
sha: str(sha, base.sha),
branch: str(branch, base.branch),
behind: counted === null ? count(base.behind) : counted,
checkedAt: str(checkedAt, base.checkedAt),
error: str(error, null),
};
}
/** What does the current revision memo mean for the operator?
*
* Split out from the header chip so the verdict is a readable table rather
* than branches buried in string concatenation — the same reason
* operatorAuthRecovery was split out of operatorAuthBannerHtml, and the same
* reason resolveCgroupMemoryDir was split out of readCgroupMemory: logic that
* can only be reached through a browser inline script or a real cgroup
* filesystem is logic that ships its bugs green.
*
* Levels:
* 'stale' — behind > 0. Landed fixes are not live; the chip warns.
* 'current' — behind === 0. Clears the chip, and clears it even when the
* latest check errored: the count reaching zero is the ONLY
* thing that clears the warning, and once it has, a later
* failed fetch has no stale count to keep showing.
* 'unknown' — no count has ever succeeded AND the check is failing. Worth
* saying out loud rather than rendering the reassuring nothing
* that an at-tip dashboard renders.
* 'unchecked' — no count yet and nothing has failed (the boot window before
* the first slow-cycle refresh). Renders nothing.
*
* Pure; no I/O. */
function classifyDashboardStaleness({ behind, error } = {}) {
const counted = (typeof behind === 'number' && Number.isFinite(behind) && behind >= 0) ? behind : null;
if (counted === null) return error ? 'unknown' : 'unchecked';
return counted > 0 ? 'stale' : 'current';
}
/** The `/data` view of the revision memo, with the staleness VERDICT resolved
* server-side.
*
* The chip is then a pure renderer: `public/index.html` is an inline browser
* script with no module boundary, so any decision left in it could only ever
* be source-scan tested — assertions on text rather than on behavior.
*
* Lives here rather than in `server.js` for the same reason
* `classifyDashboardStaleness` does: `server.js` has top-level side effects on
* require (createServer/listen/setInterval), so nothing there can be executed
* by a test and a projection defined inside it ships its bugs green.
*
* Pure; no I/O. */
function projectDashboardRevision(memo = {}) {
return { ...memo, level: classifyDashboardStaleness(memo) };
}
module.exports = {
mergeDashboardRevision,
classifyDashboardStaleness,
projectDashboardRevision,
};
import{j as e}from"./markdown-C9tbsVHX.js";import{b as a}from"./react-nrLBr15I.js";import{u as O}from"./useEvents-S3Qk1Y_d.js";import{b as E}from"./index-D_Bz8tMJ.js";function P({connected:t}){return e.jsx("span",{className:`inline-block rounded-full px-2 py-0.5 text-xs font-medium text-[var(--text-primary)] ${t?"bg-[var(--accent-green)]":"bg-[var(--accent-red)]"}`,children:t?"connected":"reconnecting…"})}const re=Object.freeze(Object.defineProperty({__proto__:null,ConnectionBadge:P},Symbol.toStringTag,{value:"Module"}));function N(){const[t,r]=a.useState(null),[o,s]=a.useState(!0),{events:l}=O(),n=a.useCallback(async()=>{try{const c=await(await fetch("/api/inspector/status")).json();r(c)}catch{}finally{s(!1)}},[]);return a.useEffect(()=>{n()},[n]),a.useEffect(()=>{const i=l[l.length-1];i&&i.type==="scenario_switch"&&n()},[l,n]),{scenario:(t==null?void 0:t.scenario)??null,previewScenario:(t==null?void 0:t.previewScenario)??null,routes:(t==null?void 0:t.routes)??[],routeCount:(t==null?void 0:t.routeCount)??0,loading:o,refetch:n}}function v({title:t}){return e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"#f0f6fc",margin:"0 0 8px 0",borderBottom:"1px solid #30363d",paddingBottom:8},children:t})}function f({color:t,children:r}){return e.jsx("span",{style:{background:`${t}22`,color:t,border:`1px solid ${t}55`,borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,letterSpacing:"0.5px",whiteSpace:"nowrap"},children:r})}const $={GET:"#D7FF63",POST:"#238636",PUT:"#d29922",DELETE:"#da3633",PATCH:"#bc8cff"};function k({method:t}){const r=$[t.toUpperCase()]??"#8b949e";return e.jsx("span",{style:{color:r,fontWeight:600,fontSize:11,minWidth:48,display:"inline-block"},children:t.toUpperCase()})}function C({color:t,children:r}){return e.jsx("div",{style:{padding:"12px 16px",borderRadius:6,border:`1px solid ${t}44`,background:`${t}11`,color:t},children:r})}const u={padding:"8px 12px",textAlign:"center",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},h={padding:"6px 12px"},S={background:"#161b22",border:"1px solid #30363d",borderRadius:6,color:"#c9d1d9",padding:"6px 12px",fontSize:13,fontFamily:"inherit"},R={...S,appearance:"none",paddingRight:24,backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b949e' d='M6 8L1 3h10z'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 8px center"},oe=Object.freeze(Object.defineProperty({__proto__:null,Badge:f,MethodBadge:k,SectionHeader:v,StatusBox:C,inputStyle:S,selectStyle:R,tdStyle:h,thStyle:u},Symbol.toStringTag,{value:"Module"}));function z({routes:t}){return e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d"},children:[e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"Pattern"}),e.jsx("th",{style:u,children:"Status"})]})}),e.jsx("tbody",{children:t.map((r,o)=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:r.method})}),e.jsx("td",{style:h,children:r.pattern}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:r.status})]},o))})]})}const se=Object.freeze(Object.defineProperty({__proto__:null,InspectorRouteTable:z},Symbol.toStringTag,{value:"Module"}));function A(){const{scenario:t,previewScenario:r,routes:o,routeCount:s,loading:l}=N();return e.jsxs("section",{children:[e.jsx(v,{title:"Active Scenario"}),l?e.jsx(C,{color:"#8b949e",children:"Loading..."}):t?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#238636",children:"ACTIVE"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:t.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",t.slug,")"]})]}),e.jsxs("div",{style:{color:"#8b949e",fontSize:12},children:[s," mock route",s!==1?"s":""," loaded"]}),o.length>0&&e.jsx(z,{routes:o})]}):r?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#D7FF63",children:"PREVIEW"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:r.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",r.slug,")"]})]}),e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"Component preview — no HTTP mocks active"})]}):e.jsx(C,{color:"#d29922",children:"No scenario active — all requests pass through to upstream"})]})}const ne=Object.freeze(Object.defineProperty({__proto__:null,InspectorScenarioSection:A},Symbol.toStringTag,{value:"Module"}));function F({textUrlFilter:t,onTextUrlFilterChange:r,methodFilter:o,onMethodFilterChange:s,sourceFilter:l,onSourceFilterChange:n}){return e.jsxs("div",{style:{display:"flex",gap:8,marginBottom:12,alignItems:"center"},children:[e.jsx("input",{type:"text",placeholder:"Filter by URL...",value:t,onChange:i=>r(i.target.value),style:{...S,flex:1,minWidth:0}}),e.jsxs("select",{value:o,onChange:i=>s(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Methods"}),e.jsx("option",{value:"GET",children:"GET"}),e.jsx("option",{value:"POST",children:"POST"}),e.jsx("option",{value:"PUT",children:"PUT"}),e.jsx("option",{value:"DELETE",children:"DELETE"}),e.jsx("option",{value:"PATCH",children:"PATCH"})]}),e.jsxs("select",{value:l,onChange:i=>n(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Sources"}),e.jsx("option",{value:"MOCKED",children:"Mocked"}),e.jsx("option",{value:"PASSTHROUGH",children:"Passthrough"})]})]})}const ie=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficFilterBar:F},Symbol.toStringTag,{value:"Module"})),G={color:"#8b949e",fontSize:11,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:4},M={background:"#161b22",border:"1px solid #30363d",borderRadius:4,padding:"8px 12px",margin:0,fontSize:11,color:"#c9d1d9",fontFamily:"monospace",maxHeight:200,overflow:"auto",whiteSpace:"pre-wrap",wordBreak:"break-all"};function _({label:t,children:r}){return e.jsxs("div",{style:{marginBottom:12},children:[e.jsx("div",{style:G,children:t}),r]})}function B({event:t}){let r=[];try{const n=new URL(t.url,"http://localhost");r=Array.from(n.searchParams.entries())}catch{}const o=t.requestHeaders&&Object.keys(t.requestHeaders).length>0,s=t.requestBody!=null,l=t.responseBody!=null;return e.jsxs("div",{style:{background:"#0d1117",padding:"12px 16px",borderTop:"1px solid #30363d"},children:[r.length>0&&e.jsx(_,{label:"Query Parameters",children:e.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"2px 12px",fontSize:12},children:r.map(([n,i],c)=>e.jsxs("div",{style:{display:"contents"},children:[e.jsx("span",{style:{color:"#D7FF63",fontFamily:"monospace"},children:n}),e.jsx("span",{style:{color:"#c9d1d9",fontFamily:"monospace"},children:i})]},c))})}),o&&e.jsx(_,{label:"Request Headers",children:e.jsx("pre",{style:M,children:Object.entries(t.requestHeaders).map(([n,i])=>`${n}: ${i}`).join(`
`)})}),s&&e.jsx(_,{label:"Request Body",children:e.jsx("pre",{style:M,children:typeof t.requestBody=="string"?t.requestBody:JSON.stringify(t.requestBody,null,2)})}),l&&e.jsx(_,{label:"Response Body",children:e.jsx("pre",{style:M,children:typeof t.responseBody=="string"?t.responseBody:JSON.stringify(t.responseBody,null,2)})}),r.length===0&&!o&&!s&&!l&&e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"No additional details available for this request"})]})}const le=Object.freeze(Object.defineProperty({__proto__:null,DetailSection:_,InspectorTrafficDetail:B},Symbol.toStringTag,{value:"Module"}));function L({event:t}){const[r,o]=a.useState(!1),s=new Date(t.timestampMs).toLocaleTimeString(),l=t.mocked;return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:()=>o(!r),style:{borderBottom:"1px solid #21262d",background:l?"transparent":"rgba(210, 153, 34, 0.05)",cursor:"pointer"},children:[e.jsxs("td",{style:{...h,color:"#8b949e",textAlign:"center"},children:[e.jsx("span",{style:{display:"inline-block",width:12,marginRight:4,fontSize:10,color:"#8b949e",transition:"transform 0.15s",transform:r?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),s]}),e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:t.method})}),e.jsx("td",{style:{...h,maxWidth:400,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.url}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:t.status??"---"}),e.jsxs("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:[t.durationMs,"ms"]}),e.jsx("td",{style:{...h,textAlign:"center"},children:l?t.mockSource==="default"?e.jsx(f,{color:"#1f6feb",children:"MOCKED (default)"}):e.jsx(f,{color:"#238636",children:"MOCKED (scenario)"}):e.jsx(f,{color:"#d29922",children:"PASSTHROUGH"})})]}),r&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,style:{padding:0},children:e.jsx(B,{event:t})})})]})}const ae=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficRow:L},Symbol.toStringTag,{value:"Module"}));function D({events:t}){return e.jsx("div",{style:{maxHeight:300,overflowY:"auto",border:"1px solid #30363d",borderRadius:6},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",position:"sticky",top:0,background:"#0d1117"},children:[e.jsx("th",{style:u,children:"Time"}),e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"URL"}),e.jsx("th",{style:u,children:"Status"}),e.jsx("th",{style:u,children:"Duration"}),e.jsx("th",{style:u,children:"Source"})]})}),e.jsx("tbody",{children:t.map(r=>e.jsx(L,{event:r},r.id))})]})})}const ce=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficTable:D},Symbol.toStringTag,{value:"Module"}));function K(t){if(t===void 0)return"checked";if(t==="checked")return"excluded"}function I({chips:t,chipStates:r,onChipStatesChange:o}){if(t.length===0)return null;const s=n=>{const i=new Map(r),c=K(i.get(n));c===void 0?i.delete(n):i.set(n,c),o(i)},l=()=>{o(new Map)};return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginBottom:12},children:[r.size>0&&e.jsx("button",{onClick:l,style:{background:"#da363322",color:"#da3633",border:"1px solid #da363355",borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,cursor:"pointer",fontFamily:"inherit"},children:"Clear all"}),t.map(({path:n,count:i})=>{const c=r.get(n),d=c==="checked",g=c==="excluded";let m="#30363d",b="#8b949e",T="#30363d",y="";return d?(m="#D7FF6322",b="#D7FF63",T="#D7FF6355",y="✓ "):g&&(m="#da363322",b="#da3633",T="#da363355",y="✗ "),e.jsxs("button",{onClick:()=>s(n),style:{background:m,color:b,border:`1px solid ${T}`,borderRadius:4,padding:"2px 8px",fontSize:11,fontFamily:"monospace",cursor:"pointer",whiteSpace:"nowrap"},children:[y,n,e.jsxs("span",{style:{marginLeft:4,opacity:.6,fontFamily:"inherit"},children:["(",i,")"]})]},n)})]})}const de=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficUrlChips:I},Symbol.toStringTag,{value:"Module"}));function H(){const{events:t}=O(),[r,o]=a.useState(""),[s,l]=a.useState(()=>new Map),[n,i]=a.useState("ALL"),[c,d]=a.useState("ALL"),g=t.filter(p=>p.type==="http_request"),m=a.useMemo(()=>{const p=new Map;for(const x of g){const j=E(x.url);p.set(j,(p.get(j)||0)+1)}return Array.from(p.entries()).sort((x,j)=>j[1]-x[1]).slice(0,10).map(([x,j])=>({path:x,count:j}))},[g]),b=a.useMemo(()=>Array.from(s.values()).some(p=>p==="checked"),[s]),y=g.filter(p=>{if(r&&!p.url.toLowerCase().includes(r.toLowerCase()))return!1;const x=E(p.url);return!(s.get(x)==="excluded"||b&&s.get(x)!=="checked"||n!=="ALL"&&p.method.toUpperCase()!==n||c==="MOCKED"&&!p.mocked||c==="PASSTHROUGH"&&p.mocked)}).slice(-50).reverse();return e.jsxs("section",{children:[e.jsx(v,{title:"Live Traffic"}),e.jsx(F,{textUrlFilter:r,onTextUrlFilterChange:o,methodFilter:n,onMethodFilterChange:i,sourceFilter:c,onSourceFilterChange:p=>d(p)}),e.jsx(I,{chips:m,chipStates:s,onChipStatesChange:l}),y.length===0?e.jsx(C,{color:"#8b949e",children:g.length>0?"No matching traffic — try adjusting the filters":"No HTTP traffic yet — requests will appear here in real-time"}):e.jsx(D,{events:y})]})}const pe=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficSection:H},Symbol.toStringTag,{value:"Module"}));function J(){const[t,r]=a.useState(null),[o,s]=a.useState(!1);return{explain:a.useCallback(async(n,i)=>{s(!0);try{const d=await(await fetch("/api/inspector/explain",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({method:n,url:i})})).json();r(d)}catch{}finally{s(!1)}},[]),result:t,loading:o}}function U({result:t}){return e.jsxs("div",{style:{border:"1px solid #30363d",borderRadius:6,padding:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsxs("span",{style:{color:"#f0f6fc",fontWeight:500},children:[t.method," ",t.url]}),t.wouldMatch?e.jsx(f,{color:"#238636",children:"WOULD MATCH"}):e.jsx(f,{color:"#da3633",children:"NO MATCH"})]}),t.attempts.length===0?e.jsx("div",{style:{color:"#8b949e"},children:"No routes loaded to match against"}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:6},children:t.attempts.map((r,o)=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",borderRadius:4,background:r.failure?"transparent":"rgba(35, 134, 54, 0.1)"},children:[e.jsx("span",{style:{color:r.failure?"#da3633":"#238636",fontWeight:600,width:16},children:r.failure?"x":"v"}),e.jsx(k,{method:r.method}),e.jsx("span",{children:r.pattern}),r.failure&&e.jsx("span",{style:{color:"#8b949e",fontSize:11},children:r.failure.reason==="methodMismatch"?`method: expected ${r.failure.expected}, got ${r.failure.actual}`:`path "${r.failure.path}" does not match "${r.failure.pattern}"`})]},o))})]})}const ue=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerResult:U},Symbol.toStringTag,{value:"Module"}));function W(){const{explain:t,result:r,loading:o}=J(),[s,l]=a.useState("GET"),[n,i]=a.useState(""),c=d=>{d.preventDefault(),n.trim()&&t(s,n.trim())};return e.jsxs("section",{children:[e.jsx(v,{title:"Match Explainer"}),e.jsxs("form",{onSubmit:c,style:{display:"flex",gap:8,marginBottom:12},children:[e.jsx("select",{value:s,onChange:d=>l(d.target.value),style:{...S,width:100},children:["GET","POST","PUT","DELETE","PATCH"].map(d=>e.jsx("option",{value:d,children:d},d))}),e.jsx("input",{type:"text",value:n,onChange:d=>i(d.target.value),placeholder:"/api/users",style:{...S,flex:1}}),e.jsx("button",{type:"submit",disabled:o||!n.trim(),style:{background:"#238636",color:"#fff",border:"none",borderRadius:6,padding:"6px 16px",cursor:"pointer",fontSize:12,fontWeight:500,opacity:o||!n.trim()?.5:1},children:o?"Checking...":"Explain"})]}),r&&e.jsx(U,{result:r})]})}const he=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerSection:W},Symbol.toStringTag,{value:"Module"})),w={"/api/health":"Health check — confirms the proxy and mock engine are running","/api/events":"SSE stream of real-time events (traffic, errors) powering this Inspector","/api/config":"Returns current CodeYam configuration for the project","/api/editor-dev-server":"Polls/controls the dev server status (start, stop, restart)","/api/inspector/status":"Returns active scenario and loaded mock routes","/api/inspector/explain":"Tests which mock route would match a given method + URL","/api/scenarios":"Lists all defined scenarios with metadata","/api/tests":"Returns the AI-maintained test registry joined with per-test-evidence, grouped by file","/api/test-results":"Returns latest test execution results","/api/screenshots/*":"Serves captured scenario screenshots","/api/session-info":"Returns current editor session metadata","/api/data-structure":"Returns the app's data structure definition","/api/dependency-graph":"Returns the project's component dependency graph","/api/app-route-entities":"Lists app routes and their associated entities","/api/glossary":"Returns the project's component glossary","/api/step":"Returns current editor workflow step","/api/editor-commands":"Lists available editor commands"};function V(t){if(w[t])return w[t];for(const[r,o]of Object.entries(w))if(r.endsWith("/*")){const s=r.slice(0,-1);if(t.startsWith(s))return o}}function Y(t){const r=new Set([...t,...Object.keys(w)]),o=[];for(const s of Array.from(r).sort()){if(s.endsWith("/*"))continue;const l=V(s);o.push({path:s,description:l??"Application endpoint"})}return o}function q(){const{events:t}=O(),r=a.useMemo(()=>{const o=[];for(const s of t)s.type==="http_request"&&o.push(E(s.url));return Y(o)},[t]);return r.length===0?null:e.jsxs("section",{children:[e.jsx(v,{title:"URL Glossary"}),e.jsx("div",{style:{border:"1px solid #30363d",borderRadius:6,overflow:"hidden"},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",background:"#161b22"},children:[e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px",width:"30%"},children:"Path"}),e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},children:"Description"})]})}),e.jsx("tbody",{children:r.map(({path:o,description:s})=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{padding:"4px 12px",fontFamily:"monospace",color:"#D7FF63",fontSize:11},children:o}),e.jsx("td",{style:{padding:"4px 12px",color:"#8b949e"},children:s})]},o))})]})})]})}const xe=Object.freeze(Object.defineProperty({__proto__:null,InspectorUrlGlossary:q},Symbol.toStringTag,{value:"Module"}));function Q(){const{connected:t}=O();return e.jsxs("div",{style:{background:"#0d1117",color:"#c9d1d9",minHeight:"100vh",fontFamily:"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace",fontSize:13,padding:24,display:"flex",flexDirection:"column",gap:24},children:[e.jsxs("header",{style:{display:"flex",alignItems:"center",gap:12},children:[e.jsx("h1",{style:{fontSize:18,fontWeight:600,color:"#f0f6fc",margin:0},children:"Container Inspector"}),e.jsx("span",{style:{color:"#8b949e",fontSize:12},children:"Read-only view of proxy and mock engine state"}),e.jsx(P,{connected:t})]}),e.jsx(A,{}),e.jsx(H,{}),e.jsx(W,{}),e.jsx(q,{})]})}const fe=Object.freeze(Object.defineProperty({__proto__:null,ContainerInspector:Q},Symbol.toStringTag,{value:"Module"}));export{f as B,Q as C,_ as D,L as I,k as M,v as S,xe as _,C as a,q as b,I as c,D as d,F as e,B as f,U as g,W as h,H as i,z as j,A as k,P as l,de as m,ce as n,pe as o,ae as p,ie as q,le as r,ne as s,u as t,se as u,oe as v,he as w,ue as x,fe as y,re as z};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import{j as c}from"./markdown-C9tbsVHX.js";import{b as o}from"./react-nrLBr15I.js";import{S as l}from"./ScenarioDataPanel-wBhNIA9N.js";function m({slug:t}){const[r,i]=o.useState(void 0);return o.useEffect(()=>{let n=!1;return fetch(`/api/scenarios/${encodeURIComponent(t)}`).then(e=>e.ok?e.json():null).then(e=>{if(n||!e)return;const a=typeof e=="object"&&e!==null&&"name"in e?String(e.name):void 0;i(a),a&&(document.title=`${a} · data`)}).catch(()=>{}),()=>{n=!0}},[t]),c.jsx(l,{slug:t,scenarioName:r,variant:"fullPage"})}const p=Object.freeze(Object.defineProperty({__proto__:null,ScenarioDataPanelFullPage:m},Symbol.toStringTag,{value:"Module"}));export{m as S,p as _};

Sorry, the diff of this file is too big to display

+123
-14

@@ -99,2 +99,63 @@ 'use strict';

// The categories that describe an add whose outcome is NOT yet proven bad — the
// calm, in-flight side of the classifier. `converging` is a rostered box whose
// ingress is still wiring; `verifying` is the residue: no failure signature
// matched and nothing durable proves the VM is dead. Both render a calm card and
// neither may use the word "failed". Consumed by holdConvergingBadge and by
// deriveStatus (server.js) to pick the matching calm status.
const CALM_ADD_CATEGORIES = new Set(['converging', 'verifying']);
// Is a non-zero add outcome CORROBORATED by a durable fact — i.e. do we have
// positive proof of death, rather than merely an absence of proof of life?
//
// This is the conjunction that gates the red `unknown` verdict. Before it, the
// classifier's fallthrough treated "no recognized success signature" as failure,
// so "we don't know" rendered as a terminal red "Add failed" telling the operator
// to destroy a VM whose container was Up and whose editor answered /api/health
// 200 (VM-4, 2026-07-31). Red now requires BOTH halves:
//
// 1. A non-zero exit code. A *missing* code is not proof of death — today it
// usually means the wrapper was signal-killed while its provision ran on,
// which is exactly the case that was misreading as failure. `null`,
// `undefined`, a non-integer, and 0 all fail this half.
// 2. At least one durable corroborating fact:
// - `instanceAlive === false` GCP says the instance is gone.
// - `containerHealthy === false` the in-VM editor was probed and is not
// answering — the box exists but never came up.
// - `wiringDeadlineBlown` the wire-add-tail gave up (the failed
// marker is the tail's own honest deadline signal).
//
// Every fact is TRI-STATE on purpose: `undefined`/`null` means "not probed" and
// corroborates nothing. Only an explicit `false` counts, so an unprobed VM can
// never be escalated to red by absence of evidence.
function addFailureCorroborated({ exitCode, instanceAlive, containerHealthy, wiringDeadlineBlown } = {}) {
const code = exitCode == null ? NaN : Number(exitCode);
if (!Number.isInteger(code) || code === 0) return false;
return instanceAlive === false || containerHealthy === false || !!wiringDeadlineBlown;
}
// Resolve the two independent health signals into the single tri-state
// `containerHealthy` fact addFailureCorroborated consumes. Pure so the precedence
// — which decides whether a VM can be escalated to red — is unit-tested; the
// server (addFailureFacts) supplies the live signals.
//
// reachable the editor answered over the LB.
// inVmHealthy the STRAND_PROBE /api/health read from INSIDE the container.
//
// LB reachability wins when present: it is the stronger witness (it proves the
// whole URL→ingress→backend path, not just the process). Otherwise the in-VM
// witness answers — this is the still-wiring case, where the LB necessarily
// cannot see a VM whose ingress is what we are waiting on, yet the editor itself
// is demonstrably up.
//
// Returns `null` when NEITHER signal was gathered. That is the load-bearing case:
// an unprobed VM must corroborate nothing, so it can never be escalated to red by
// absence of evidence. `false` is reserved for a VM that was genuinely probed and
// did not answer.
function containerHealthWitness({ reachable, inVmHealthy } = {}) {
if (reachable) return true;
if (inVmHealthy != null) return !!inVmHealthy;
return null;
}
// Build a verdict, stamping `retryable` from the single-source-of-truth Set so it

@@ -112,4 +173,13 @@ // can never drift from the category.

// log was unreadable — must never throw)
// exitCode the provision's exit code (number; used for signal-kill detection)
// exitCode the provision's exit code (number; used for signal-kill detection
// and as the first half of the proof-of-death conjunction)
//
// The remaining inputs are the durable facts the server gathers (the module
// stays pure — it never probes). All are tri-state; omit any that was not
// probed and it corroborates nothing. See addFailureCorroborated.
//
// instanceAlive does GCP still list the instance?
// containerHealthy did the in-VM editor answer /api/health?
// wiringDeadlineBlown did the add-time wire tail drop its failed marker?
//
// Returns { category, headline, recovery, retryable, files? }.

@@ -123,3 +193,3 @@ //

// operator would lose the safe one-click recovery.
function classifyAddFailure({ logTail, exitCode } = {}) {
function classifyAddFailure({ logTail, exitCode, instanceAlive, containerHealthy, wiringDeadlineBlown } = {}) {
const log = String(logTail || '');

@@ -224,5 +294,30 @@

// 9. unknown — fallback. Never invite an unproven retry.
return buildFailureVerdict('unknown', 'Add failed',
'The add failed for an unclassified reason — inspect the transcript below, then reconcile or destroy this VM before re-adding.');
// 9. The residue: no failure signature above matched. The polarity here is
// INVERTED from the original design. It used to read "no recognized success
// signature ⇒ failed", which made red the DEFAULT for "we don't know" — so a
// VM whose container was Up and whose editor answered /api/health 200 got a
// terminal red "Add failed" card advising the operator to destroy it (VM-4,
// 2026-07-31; the wrapper had been killed mid-flight, so its transcript was
// truncated before CY_ROSTER and it never reached the `converging` arm above).
//
// Red now requires positive proof of death, and everything else is in-flight:
//
// 9a. unknown — a non-zero exit CORROBORATED by a durable fact (see
// addFailureCorroborated). The box is provably dead or provably never
// came up, so the loud, terminal escalation is warranted and unchanged.
// Still never invites an unproven retry.
if (addFailureCorroborated({ exitCode, instanceAlive, containerHealthy, wiringDeadlineBlown })) {
return buildFailureVerdict('unknown', 'Add failed',
'The add failed for an unclassified reason and the VM is confirmed dead or never came up — inspect the transcript below, then reconcile or destroy this VM before re-adding.');
}
// 9b. verifying — the honest default. No failure signature, and nothing
// durable proves this VM is dead: it may still be provisioning or
// wiring, and the ingress can keep propagating for minutes after the
// wrapper is gone. Calm copy, transcript still one click away. NOT
// retryable — nothing is proven about the box either way, so a one-click
// retry could still duplicate a live GCP instance (the ADD_FAILURE_RETRYABLE
// grounds are unchanged by this inversion).
return buildFailureVerdict('verifying', 'Add outcome unconfirmed',
'No failure signature was found in the transcript and nothing proves this VM is dead, so the add may still be converging — the ingress keeps propagating for minutes after the provision wrapper exits. Inspect the transcript below; reconcile this VM only if it is still unresolved past the wiring deadline.');
}

@@ -245,13 +340,27 @@

// Pure badge-hold predicate for deriveStatus (server.js): hold the calm in-flight
// `add-converging` card — instead of the red add-failed — ONLY when the add was
// classified `converging` AND its detached first-wiring is still in flight. Once
// the wire-add-tail fails/deadlines (`addTailFailed`) or is gone (`addTailInflight`
// false), or the category is anything else, return false so the caller falls
// through to the red add-failed status — the operator-chosen escalation. Kept pure
// (like canRetryAdd / canClearBadge) so the badge decision is unit-tested without a
// card — instead of the red add-failed — while the add is still converging.
//
// The hold used to require `addTailInflight`, i.e. that the detached wire-add-tail
// PROCESS was still alive. That premise was wrong: the tail's exit says nothing
// about LB convergence, because the EXTERNAL_MANAGED backend services keep
// propagating for minutes afterwards. VM-4's backends were still being created at
// 18:17-18:20Z, long after its job had been declared failed at 18:15Z — the tail
// had exited, so the calm hold released and the card went red on a healthy VM.
//
// The hold is now driven by the question that actually matters: is this add still
// converging, and has its wiring deadline genuinely blown? `wiringDeadlineBlown`
// (the failed marker the tail drops when it gives up) stays the release signal —
// tail liveness is no longer a requirement for calm, so the calm state survives
// the multi-minute propagation window instead of ending at process exit.
//
// Both calm categories qualify (see CALM_ADD_CATEGORIES): a rostered box that is
// still wiring, and the unproven residue. Any proven-failure category returns
// false and falls through to the red add-failed status — the operator-chosen
// escalation, which this predicate narrows but never softens. Kept pure (like
// canRetryAdd / canClearBadge) so the badge decision is unit-tested without a
// live dashboard.
function holdConvergingBadge({ category, addTailInflight, addTailFailed } = {}) {
return category === 'converging' && !!addTailInflight && !addTailFailed;
function holdConvergingBadge({ category, wiringDeadlineBlown } = {}) {
return CALM_ADD_CATEGORIES.has(category) && !wiringDeadlineBlown;
}
module.exports = { classifyAddFailure, extractDriftFiles, lastNonEmptyLines, canRetryAdd, transcriptRostered, holdConvergingBadge, ADD_FAILURE_RETRYABLE };
module.exports = { classifyAddFailure, extractDriftFiles, lastNonEmptyLines, canRetryAdd, transcriptRostered, holdConvergingBadge, addFailureCorroborated, containerHealthWitness, CALM_ADD_CATEGORIES, ADD_FAILURE_RETRYABLE };
+28
-12

@@ -18,17 +18,33 @@ 'use strict';

//
// job the carried job record ({ state, action, ... }) or null
// reachable the VM's editor answered this poll (true = healthy / responding)
// drifted a project-dir-drift signal is present (reachable-but-unwired /
// half-provisioned add — genuinely needs-recovery, owned by the
// companion reconcile-inflight-jobs plan; never falsely cleared here)
// offBranch the VM's live client branch differs from its target branch
// degraded the job completed but a wiring sub-step is flagged degraded
// job the carried job record ({ state, action, ... }) or null
// reachable the VM's editor answered this poll over the LB (true = healthy)
// inVmHealthy the in-VM editor answered /api/health from INSIDE the container
// (the STRAND_PROBE `HEALTH=1` witness gathered over docker-exec)
// drifted a project-dir-drift signal is present (reachable-but-unwired /
// half-provisioned add — genuinely needs-recovery, owned by the
// companion reconcile-inflight-jobs plan; never falsely cleared here)
// offBranch the VM's live client branch differs from its target branch
// degraded the job completed but a wiring sub-step is flagged degraded
//
// Returns true only when the job is a terminal error AND the VM is demonstrably
// fine (reachable, not drifted, on-branch, not degraded). An unreachable /
// drifted / off-branch VM keeps its error surfaced — a real problem must stay
// visible.
function shouldReconcileFailedBadge({ job, reachable, drifted, offBranch, degraded } = {}) {
// fine (healthy, not drifted, on-branch, not degraded). A drifted / off-branch /
// unwitnessed VM keeps its error surfaced — a real problem must stay visible.
//
// HEALTH IS WITNESSED TWO WAYS, and either suffices. `reachable` alone made the
// self-heal unable to fire in exactly the case that needs it most: on the GCE
// operator host `reachable` is derived from the LB probe, which needs the very
// ingress the add is still wiring. That is a circular dependency — the badge
// needs reachable, reachable needs ingress, and ingress is what we are waiting
// for — so a still-wiring VM sat at unreachableStreak 9 with a red add-error it
// could not clear by construction (VM-4, 2026-07-31). The dashboard already held
// the disconfirming evidence: gatherLauncherStrand runs STRAND_PROBE over
// docker-exec for exactly these unreachable-with-streak VMs and reads HEALTH=1
// from the in-VM /api/health.
//
// This widens ONE input; it does not relax the verdict. Every other guard is
// untouched, and the "absence of evidence never auto-acts" posture holds — an
// unprobed VM has neither witness and stays unreconciled.
function shouldReconcileFailedBadge({ job, reachable, inVmHealthy, drifted, offBranch, degraded } = {}) {
if (!job || job.state !== 'error') return false;
if (!reachable) return false;
if (!reachable && !inVmHealthy) return false;
if (drifted) return false;

@@ -35,0 +51,0 @@ if (offBranch) return false;

@@ -359,2 +359,45 @@ 'use strict';

/** Resolve the directory holding THIS process's memory.current / memory.high,
* or null when no cgroup-derived reading is available.
*
* The cgroup-v2 hierarchy ROOT exposes no memory.current and no memory.high —
* only a leaf cgroup does. Reading `/sys/fs/cgroup/memory.current` directly is
* therefore ENOENT on every systemd host, and that is exactly what made the
* 2026-07-30 memory remedy inert: both reads failed, every cgroup number
* degraded to null, decideMemoryRestart answered 'no-cgroup-limit' on every
* tick forever, and the drain silently fell back to the RSS threshold the
* incident had already proven cannot fire before the event loop stalls.
*
* Takes the CONTENTS of /proc/self/cgroup rather than reading it, so the path
* derivation — the part that was wrong — is unit-testable on a macOS dev box
* with no cgroup filesystem at all. That untestability is why a root-vs-leaf
* path error shipped green.
*
* Returns null for every shape that has no leaf memory file to read:
* • the unified line `0::/` — the process IS in the root cgroup, which
* genuinely has no memory files; this must NOT look like a valid path;
* • cgroup v1 (`N:controller:/path` lines, no `0::` entry);
* • empty, unreadable, or malformed input (a non-Linux host has no
* /proc/self/cgroup at all, and the caller passes the null through).
*
* Pure; no I/O. */
function resolveCgroupMemoryDir({ procSelfCgroup, root } = {}) {
if (typeof procSelfCgroup !== 'string') return null;
const base = (typeof root === 'string' && root)
? root.replace(/\/+$/, '')
: '/sys/fs/cgroup';
for (const line of procSelfCgroup.split('\n')) {
const trimmed = line.trim();
// cgroup v2 unified hierarchy is the single `0::<path>` entry. v1 lines
// (`N:controller:/path`) never match, which is the intended null path.
if (!trimmed.startsWith('0::')) continue;
const rel = trimmed.slice(3);
if (!rel.startsWith('/')) return null;
const clean = rel.replace(/\/+$/, '');
if (!clean) return null;
return base + clean;
}
return null;
}
/** Keep only the restart timestamps still inside the rolling window.

@@ -390,2 +433,3 @@ *

shouldAnnounceMemoryLevel,
resolveCgroupMemoryDir,
pruneRestartWindow,

@@ -392,0 +436,0 @@ buildStateSnapshot,

'use strict';
// Resolve the running-plan fields a fleet card shows — feature, step, mode,
// selectedPlan, holderSessionId — from the two independent per-VM probes plus
// the last-known-good state.
// selectedPlan, holderSessionId, startedAt, featureStartedAt — from the two
// independent per-VM probes plus the last-known-good state.
//
// The two timestamps ride here because they share the restart problem below and
// nothing else resolves them: `startedAt` / `featureStartedAt` drive the card's
// "on step" / "on feature" tenure badges AND the server-side slow/stuck/needs-you
// verdict (fleet-stuck-status.js deriveAttention keys on `startedAt`). A null
// degrades that verdict to level:'ok', needsYou:false — so a VM whose editor
// restarted was silently exempt from the very detection it most needed.
//
// Why this exists: the card used to hang these fields off `/api/session-info`

@@ -38,6 +45,7 @@ // alone (spread as `...info` in server.js). But a VM whose editor server

// @param {?Object} params.prev The previous `state.vms[n]` (carries the
// last-known feature/step/mode/selectedPlan/holderSessionId). null/undefined
// on the first poll.
// last-known feature/step/mode/selectedPlan/holderSessionId/startedAt/
// featureStartedAt). null/undefined on the first poll.
// @returns {{feature: ?string, step: ?number, mode: ?string,
// selectedPlan: ?string, holderSessionId: ?string}}
// selectedPlan: ?string, holderSessionId: ?string, startedAt: ?string,
// featureStartedAt: ?string}}
function resolveRunningPlan({ step, info, prev } = {}) {

@@ -60,2 +68,6 @@ const s = step || {};

holderSessionId: p.holderSessionId || null,
// Carried verbatim like the rest: a single timed-out cycle must not blink
// the tenure badges off and reset the stuck timer back to zero.
startedAt: p.startedAt || null,
featureStartedAt: p.featureStartedAt || null,
};

@@ -72,2 +84,11 @@ }

// The module's precedence rule, in ONE place: /api/step (session-independent)
// > /api/session-info > same-plan carry. Four fields resolve exactly this way,
// so hoisting it keeps a future precedence change from being applied to some
// of them and not others. The two fields that deviate stay longhand below, and
// their being longhand is the signal that they deviate: `step` needs an
// explicit null check (0 is a real step number, and `||` would swallow it),
// and holderSessionId deliberately skips session-info, which never carries it.
const pick = (key) => s[key] || i[key] || carry[key] || null;
const stepNum =

@@ -77,5 +98,5 @@ s.step != null ? s.step : i.step != null ? i.step : carry.step != null ? carry.step : null;

return {
feature: s.feature || i.feature || carry.feature || null,
feature: pick("feature"),
step: stepNum,
mode: s.mode || i.mode || carry.mode || null,
mode: pick("mode"),
selectedPlan: freshSelectedPlan || carry.selectedPlan || null,

@@ -86,2 +107,11 @@ // session-info never carries holderSessionId — it comes from /api/step

holderSessionId: s.holderSessionId || carry.holderSessionId || null,
// Workflow tenure timers. /api/step wins because EditorStepState serializes
// `started_at` (non-optional, camelCase) straight out of editor-step.json —
// session-independent, so it survives the editor restart that makes
// session-info report hasSession:false and omit them entirely. The same-plan
// `carry` applies unchanged: a completed plan's startedAt must never be
// pinned onto the next plan, or the badges would show a tenure the new plan
// has not accrued.
startedAt: pick("startedAt"),
featureStartedAt: pick("featureStartedAt"),
};

@@ -88,0 +118,0 @@ }

{
"name": "@codeyam-editor/codeyam-editor",
"version": "0.1.0-staging.g25ba0d1",
"version": "0.1.0-staging.g296f8a2",
"description": "Language-agnostic managed execution sandbox for scenario-driven development",

@@ -12,6 +12,6 @@ "bin": {

"optionalDependencies": {
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.0-staging.g25ba0d1",
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.0-staging.g25ba0d1",
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.0-staging.g25ba0d1",
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.0-staging.g25ba0d1"
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.0-staging.g296f8a2",
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.0-staging.g296f8a2",
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.0-staging.g296f8a2",
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.0-staging.g296f8a2"
},

@@ -18,0 +18,0 @@ "keywords": [

@@ -8,3 +8,3 @@ <!DOCTYPE html>

<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<script type="module" crossorigin src="/assets/index-DCHqRrwO.js"></script>
<script type="module" crossorigin src="/assets/index-D_Bz8tMJ.js"></script>
<link rel="modulepreload" crossorigin href="/assets/react-nrLBr15I.js">

@@ -11,0 +11,0 @@ <link rel="modulepreload" crossorigin href="/assets/markdown-C9tbsVHX.js">

import{j as e}from"./markdown-C9tbsVHX.js";import{b as a}from"./react-nrLBr15I.js";import{u as O}from"./useEvents-S3Qk1Y_d.js";import{b as E}from"./index-DCHqRrwO.js";function P({connected:t}){return e.jsx("span",{className:`inline-block rounded-full px-2 py-0.5 text-xs font-medium text-[var(--text-primary)] ${t?"bg-[var(--accent-green)]":"bg-[var(--accent-red)]"}`,children:t?"connected":"reconnecting…"})}const re=Object.freeze(Object.defineProperty({__proto__:null,ConnectionBadge:P},Symbol.toStringTag,{value:"Module"}));function N(){const[t,r]=a.useState(null),[o,s]=a.useState(!0),{events:l}=O(),n=a.useCallback(async()=>{try{const c=await(await fetch("/api/inspector/status")).json();r(c)}catch{}finally{s(!1)}},[]);return a.useEffect(()=>{n()},[n]),a.useEffect(()=>{const i=l[l.length-1];i&&i.type==="scenario_switch"&&n()},[l,n]),{scenario:(t==null?void 0:t.scenario)??null,previewScenario:(t==null?void 0:t.previewScenario)??null,routes:(t==null?void 0:t.routes)??[],routeCount:(t==null?void 0:t.routeCount)??0,loading:o,refetch:n}}function v({title:t}){return e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"#f0f6fc",margin:"0 0 8px 0",borderBottom:"1px solid #30363d",paddingBottom:8},children:t})}function f({color:t,children:r}){return e.jsx("span",{style:{background:`${t}22`,color:t,border:`1px solid ${t}55`,borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,letterSpacing:"0.5px",whiteSpace:"nowrap"},children:r})}const $={GET:"#D7FF63",POST:"#238636",PUT:"#d29922",DELETE:"#da3633",PATCH:"#bc8cff"};function k({method:t}){const r=$[t.toUpperCase()]??"#8b949e";return e.jsx("span",{style:{color:r,fontWeight:600,fontSize:11,minWidth:48,display:"inline-block"},children:t.toUpperCase()})}function C({color:t,children:r}){return e.jsx("div",{style:{padding:"12px 16px",borderRadius:6,border:`1px solid ${t}44`,background:`${t}11`,color:t},children:r})}const u={padding:"8px 12px",textAlign:"center",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},h={padding:"6px 12px"},S={background:"#161b22",border:"1px solid #30363d",borderRadius:6,color:"#c9d1d9",padding:"6px 12px",fontSize:13,fontFamily:"inherit"},R={...S,appearance:"none",paddingRight:24,backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b949e' d='M6 8L1 3h10z'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 8px center"},oe=Object.freeze(Object.defineProperty({__proto__:null,Badge:f,MethodBadge:k,SectionHeader:v,StatusBox:C,inputStyle:S,selectStyle:R,tdStyle:h,thStyle:u},Symbol.toStringTag,{value:"Module"}));function z({routes:t}){return e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d"},children:[e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"Pattern"}),e.jsx("th",{style:u,children:"Status"})]})}),e.jsx("tbody",{children:t.map((r,o)=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:r.method})}),e.jsx("td",{style:h,children:r.pattern}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:r.status})]},o))})]})}const se=Object.freeze(Object.defineProperty({__proto__:null,InspectorRouteTable:z},Symbol.toStringTag,{value:"Module"}));function A(){const{scenario:t,previewScenario:r,routes:o,routeCount:s,loading:l}=N();return e.jsxs("section",{children:[e.jsx(v,{title:"Active Scenario"}),l?e.jsx(C,{color:"#8b949e",children:"Loading..."}):t?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#238636",children:"ACTIVE"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:t.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",t.slug,")"]})]}),e.jsxs("div",{style:{color:"#8b949e",fontSize:12},children:[s," mock route",s!==1?"s":""," loaded"]}),o.length>0&&e.jsx(z,{routes:o})]}):r?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#D7FF63",children:"PREVIEW"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:r.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",r.slug,")"]})]}),e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"Component preview — no HTTP mocks active"})]}):e.jsx(C,{color:"#d29922",children:"No scenario active — all requests pass through to upstream"})]})}const ne=Object.freeze(Object.defineProperty({__proto__:null,InspectorScenarioSection:A},Symbol.toStringTag,{value:"Module"}));function F({textUrlFilter:t,onTextUrlFilterChange:r,methodFilter:o,onMethodFilterChange:s,sourceFilter:l,onSourceFilterChange:n}){return e.jsxs("div",{style:{display:"flex",gap:8,marginBottom:12,alignItems:"center"},children:[e.jsx("input",{type:"text",placeholder:"Filter by URL...",value:t,onChange:i=>r(i.target.value),style:{...S,flex:1,minWidth:0}}),e.jsxs("select",{value:o,onChange:i=>s(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Methods"}),e.jsx("option",{value:"GET",children:"GET"}),e.jsx("option",{value:"POST",children:"POST"}),e.jsx("option",{value:"PUT",children:"PUT"}),e.jsx("option",{value:"DELETE",children:"DELETE"}),e.jsx("option",{value:"PATCH",children:"PATCH"})]}),e.jsxs("select",{value:l,onChange:i=>n(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Sources"}),e.jsx("option",{value:"MOCKED",children:"Mocked"}),e.jsx("option",{value:"PASSTHROUGH",children:"Passthrough"})]})]})}const ie=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficFilterBar:F},Symbol.toStringTag,{value:"Module"})),G={color:"#8b949e",fontSize:11,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:4},M={background:"#161b22",border:"1px solid #30363d",borderRadius:4,padding:"8px 12px",margin:0,fontSize:11,color:"#c9d1d9",fontFamily:"monospace",maxHeight:200,overflow:"auto",whiteSpace:"pre-wrap",wordBreak:"break-all"};function _({label:t,children:r}){return e.jsxs("div",{style:{marginBottom:12},children:[e.jsx("div",{style:G,children:t}),r]})}function B({event:t}){let r=[];try{const n=new URL(t.url,"http://localhost");r=Array.from(n.searchParams.entries())}catch{}const o=t.requestHeaders&&Object.keys(t.requestHeaders).length>0,s=t.requestBody!=null,l=t.responseBody!=null;return e.jsxs("div",{style:{background:"#0d1117",padding:"12px 16px",borderTop:"1px solid #30363d"},children:[r.length>0&&e.jsx(_,{label:"Query Parameters",children:e.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"2px 12px",fontSize:12},children:r.map(([n,i],c)=>e.jsxs("div",{style:{display:"contents"},children:[e.jsx("span",{style:{color:"#D7FF63",fontFamily:"monospace"},children:n}),e.jsx("span",{style:{color:"#c9d1d9",fontFamily:"monospace"},children:i})]},c))})}),o&&e.jsx(_,{label:"Request Headers",children:e.jsx("pre",{style:M,children:Object.entries(t.requestHeaders).map(([n,i])=>`${n}: ${i}`).join(`
`)})}),s&&e.jsx(_,{label:"Request Body",children:e.jsx("pre",{style:M,children:typeof t.requestBody=="string"?t.requestBody:JSON.stringify(t.requestBody,null,2)})}),l&&e.jsx(_,{label:"Response Body",children:e.jsx("pre",{style:M,children:typeof t.responseBody=="string"?t.responseBody:JSON.stringify(t.responseBody,null,2)})}),r.length===0&&!o&&!s&&!l&&e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"No additional details available for this request"})]})}const le=Object.freeze(Object.defineProperty({__proto__:null,DetailSection:_,InspectorTrafficDetail:B},Symbol.toStringTag,{value:"Module"}));function L({event:t}){const[r,o]=a.useState(!1),s=new Date(t.timestampMs).toLocaleTimeString(),l=t.mocked;return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:()=>o(!r),style:{borderBottom:"1px solid #21262d",background:l?"transparent":"rgba(210, 153, 34, 0.05)",cursor:"pointer"},children:[e.jsxs("td",{style:{...h,color:"#8b949e",textAlign:"center"},children:[e.jsx("span",{style:{display:"inline-block",width:12,marginRight:4,fontSize:10,color:"#8b949e",transition:"transform 0.15s",transform:r?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),s]}),e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:t.method})}),e.jsx("td",{style:{...h,maxWidth:400,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.url}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:t.status??"---"}),e.jsxs("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:[t.durationMs,"ms"]}),e.jsx("td",{style:{...h,textAlign:"center"},children:l?t.mockSource==="default"?e.jsx(f,{color:"#1f6feb",children:"MOCKED (default)"}):e.jsx(f,{color:"#238636",children:"MOCKED (scenario)"}):e.jsx(f,{color:"#d29922",children:"PASSTHROUGH"})})]}),r&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,style:{padding:0},children:e.jsx(B,{event:t})})})]})}const ae=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficRow:L},Symbol.toStringTag,{value:"Module"}));function D({events:t}){return e.jsx("div",{style:{maxHeight:300,overflowY:"auto",border:"1px solid #30363d",borderRadius:6},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",position:"sticky",top:0,background:"#0d1117"},children:[e.jsx("th",{style:u,children:"Time"}),e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"URL"}),e.jsx("th",{style:u,children:"Status"}),e.jsx("th",{style:u,children:"Duration"}),e.jsx("th",{style:u,children:"Source"})]})}),e.jsx("tbody",{children:t.map(r=>e.jsx(L,{event:r},r.id))})]})})}const ce=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficTable:D},Symbol.toStringTag,{value:"Module"}));function K(t){if(t===void 0)return"checked";if(t==="checked")return"excluded"}function I({chips:t,chipStates:r,onChipStatesChange:o}){if(t.length===0)return null;const s=n=>{const i=new Map(r),c=K(i.get(n));c===void 0?i.delete(n):i.set(n,c),o(i)},l=()=>{o(new Map)};return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginBottom:12},children:[r.size>0&&e.jsx("button",{onClick:l,style:{background:"#da363322",color:"#da3633",border:"1px solid #da363355",borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,cursor:"pointer",fontFamily:"inherit"},children:"Clear all"}),t.map(({path:n,count:i})=>{const c=r.get(n),d=c==="checked",g=c==="excluded";let m="#30363d",b="#8b949e",T="#30363d",y="";return d?(m="#D7FF6322",b="#D7FF63",T="#D7FF6355",y="✓ "):g&&(m="#da363322",b="#da3633",T="#da363355",y="✗ "),e.jsxs("button",{onClick:()=>s(n),style:{background:m,color:b,border:`1px solid ${T}`,borderRadius:4,padding:"2px 8px",fontSize:11,fontFamily:"monospace",cursor:"pointer",whiteSpace:"nowrap"},children:[y,n,e.jsxs("span",{style:{marginLeft:4,opacity:.6,fontFamily:"inherit"},children:["(",i,")"]})]},n)})]})}const de=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficUrlChips:I},Symbol.toStringTag,{value:"Module"}));function H(){const{events:t}=O(),[r,o]=a.useState(""),[s,l]=a.useState(()=>new Map),[n,i]=a.useState("ALL"),[c,d]=a.useState("ALL"),g=t.filter(p=>p.type==="http_request"),m=a.useMemo(()=>{const p=new Map;for(const x of g){const j=E(x.url);p.set(j,(p.get(j)||0)+1)}return Array.from(p.entries()).sort((x,j)=>j[1]-x[1]).slice(0,10).map(([x,j])=>({path:x,count:j}))},[g]),b=a.useMemo(()=>Array.from(s.values()).some(p=>p==="checked"),[s]),y=g.filter(p=>{if(r&&!p.url.toLowerCase().includes(r.toLowerCase()))return!1;const x=E(p.url);return!(s.get(x)==="excluded"||b&&s.get(x)!=="checked"||n!=="ALL"&&p.method.toUpperCase()!==n||c==="MOCKED"&&!p.mocked||c==="PASSTHROUGH"&&p.mocked)}).slice(-50).reverse();return e.jsxs("section",{children:[e.jsx(v,{title:"Live Traffic"}),e.jsx(F,{textUrlFilter:r,onTextUrlFilterChange:o,methodFilter:n,onMethodFilterChange:i,sourceFilter:c,onSourceFilterChange:p=>d(p)}),e.jsx(I,{chips:m,chipStates:s,onChipStatesChange:l}),y.length===0?e.jsx(C,{color:"#8b949e",children:g.length>0?"No matching traffic — try adjusting the filters":"No HTTP traffic yet — requests will appear here in real-time"}):e.jsx(D,{events:y})]})}const pe=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficSection:H},Symbol.toStringTag,{value:"Module"}));function J(){const[t,r]=a.useState(null),[o,s]=a.useState(!1);return{explain:a.useCallback(async(n,i)=>{s(!0);try{const d=await(await fetch("/api/inspector/explain",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({method:n,url:i})})).json();r(d)}catch{}finally{s(!1)}},[]),result:t,loading:o}}function U({result:t}){return e.jsxs("div",{style:{border:"1px solid #30363d",borderRadius:6,padding:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsxs("span",{style:{color:"#f0f6fc",fontWeight:500},children:[t.method," ",t.url]}),t.wouldMatch?e.jsx(f,{color:"#238636",children:"WOULD MATCH"}):e.jsx(f,{color:"#da3633",children:"NO MATCH"})]}),t.attempts.length===0?e.jsx("div",{style:{color:"#8b949e"},children:"No routes loaded to match against"}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:6},children:t.attempts.map((r,o)=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",borderRadius:4,background:r.failure?"transparent":"rgba(35, 134, 54, 0.1)"},children:[e.jsx("span",{style:{color:r.failure?"#da3633":"#238636",fontWeight:600,width:16},children:r.failure?"x":"v"}),e.jsx(k,{method:r.method}),e.jsx("span",{children:r.pattern}),r.failure&&e.jsx("span",{style:{color:"#8b949e",fontSize:11},children:r.failure.reason==="methodMismatch"?`method: expected ${r.failure.expected}, got ${r.failure.actual}`:`path "${r.failure.path}" does not match "${r.failure.pattern}"`})]},o))})]})}const ue=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerResult:U},Symbol.toStringTag,{value:"Module"}));function W(){const{explain:t,result:r,loading:o}=J(),[s,l]=a.useState("GET"),[n,i]=a.useState(""),c=d=>{d.preventDefault(),n.trim()&&t(s,n.trim())};return e.jsxs("section",{children:[e.jsx(v,{title:"Match Explainer"}),e.jsxs("form",{onSubmit:c,style:{display:"flex",gap:8,marginBottom:12},children:[e.jsx("select",{value:s,onChange:d=>l(d.target.value),style:{...S,width:100},children:["GET","POST","PUT","DELETE","PATCH"].map(d=>e.jsx("option",{value:d,children:d},d))}),e.jsx("input",{type:"text",value:n,onChange:d=>i(d.target.value),placeholder:"/api/users",style:{...S,flex:1}}),e.jsx("button",{type:"submit",disabled:o||!n.trim(),style:{background:"#238636",color:"#fff",border:"none",borderRadius:6,padding:"6px 16px",cursor:"pointer",fontSize:12,fontWeight:500,opacity:o||!n.trim()?.5:1},children:o?"Checking...":"Explain"})]}),r&&e.jsx(U,{result:r})]})}const he=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerSection:W},Symbol.toStringTag,{value:"Module"})),w={"/api/health":"Health check — confirms the proxy and mock engine are running","/api/events":"SSE stream of real-time events (traffic, errors) powering this Inspector","/api/config":"Returns current CodeYam configuration for the project","/api/editor-dev-server":"Polls/controls the dev server status (start, stop, restart)","/api/inspector/status":"Returns active scenario and loaded mock routes","/api/inspector/explain":"Tests which mock route would match a given method + URL","/api/scenarios":"Lists all defined scenarios with metadata","/api/tests":"Returns the AI-maintained test registry joined with per-test-evidence, grouped by file","/api/test-results":"Returns latest test execution results","/api/screenshots/*":"Serves captured scenario screenshots","/api/session-info":"Returns current editor session metadata","/api/data-structure":"Returns the app's data structure definition","/api/dependency-graph":"Returns the project's component dependency graph","/api/app-route-entities":"Lists app routes and their associated entities","/api/glossary":"Returns the project's component glossary","/api/step":"Returns current editor workflow step","/api/editor-commands":"Lists available editor commands"};function V(t){if(w[t])return w[t];for(const[r,o]of Object.entries(w))if(r.endsWith("/*")){const s=r.slice(0,-1);if(t.startsWith(s))return o}}function Y(t){const r=new Set([...t,...Object.keys(w)]),o=[];for(const s of Array.from(r).sort()){if(s.endsWith("/*"))continue;const l=V(s);o.push({path:s,description:l??"Application endpoint"})}return o}function q(){const{events:t}=O(),r=a.useMemo(()=>{const o=[];for(const s of t)s.type==="http_request"&&o.push(E(s.url));return Y(o)},[t]);return r.length===0?null:e.jsxs("section",{children:[e.jsx(v,{title:"URL Glossary"}),e.jsx("div",{style:{border:"1px solid #30363d",borderRadius:6,overflow:"hidden"},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",background:"#161b22"},children:[e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px",width:"30%"},children:"Path"}),e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},children:"Description"})]})}),e.jsx("tbody",{children:r.map(({path:o,description:s})=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{padding:"4px 12px",fontFamily:"monospace",color:"#D7FF63",fontSize:11},children:o}),e.jsx("td",{style:{padding:"4px 12px",color:"#8b949e"},children:s})]},o))})]})})]})}const xe=Object.freeze(Object.defineProperty({__proto__:null,InspectorUrlGlossary:q},Symbol.toStringTag,{value:"Module"}));function Q(){const{connected:t}=O();return e.jsxs("div",{style:{background:"#0d1117",color:"#c9d1d9",minHeight:"100vh",fontFamily:"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace",fontSize:13,padding:24,display:"flex",flexDirection:"column",gap:24},children:[e.jsxs("header",{style:{display:"flex",alignItems:"center",gap:12},children:[e.jsx("h1",{style:{fontSize:18,fontWeight:600,color:"#f0f6fc",margin:0},children:"Container Inspector"}),e.jsx("span",{style:{color:"#8b949e",fontSize:12},children:"Read-only view of proxy and mock engine state"}),e.jsx(P,{connected:t})]}),e.jsx(A,{}),e.jsx(H,{}),e.jsx(W,{}),e.jsx(q,{})]})}const fe=Object.freeze(Object.defineProperty({__proto__:null,ContainerInspector:Q},Symbol.toStringTag,{value:"Module"}));export{f as B,Q as C,_ as D,L as I,k as M,v as S,xe as _,C as a,q as b,I as c,D as d,F as e,B as f,U as g,W as h,H as i,z as j,A as k,P as l,de as m,ce as n,pe as o,ae as p,ie as q,le as r,ne as s,u as t,se as u,oe as v,he as w,ue as x,fe as y,re as z};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import{j as c}from"./markdown-C9tbsVHX.js";import{b as o}from"./react-nrLBr15I.js";import{S as l}from"./ScenarioDataPanel-BeQfa28g.js";function m({slug:t}){const[r,i]=o.useState(void 0);return o.useEffect(()=>{let n=!1;return fetch(`/api/scenarios/${encodeURIComponent(t)}`).then(e=>e.ok?e.json():null).then(e=>{if(n||!e)return;const a=typeof e=="object"&&e!==null&&"name"in e?String(e.name):void 0;i(a),a&&(document.title=`${a} · data`)}).catch(()=>{}),()=>{n=!0}},[t]),c.jsx(l,{slug:t,scenarioName:r,variant:"fullPage"})}const p=Object.freeze(Object.defineProperty({__proto__:null,ScenarioDataPanelFullPage:m},Symbol.toStringTag,{value:"Module"}));export{m as S,p as _};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display