@codeyam-editor/codeyam-editor 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/npm/cloud.js +192 -29
  2. package/npm/compose-conflict.js +59 -0
  3. package/npm/fleet-add-failure.js +123 -14
  4. package/npm/fleet-cleanup.js +129 -0
  5. package/npm/fleet-job-badge.js +28 -12
  6. package/npm/fleet-memory.js +44 -0
  7. package/npm/fleet-probe-transport.js +155 -0
  8. package/npm/fleet-revision.js +104 -0
  9. package/npm/fleet-running-plan.js +37 -7
  10. package/npm/launch-config.js +120 -4
  11. package/npm/scenario-check.js +52 -18
  12. package/npm/scenario-playwright.js +44 -10
  13. package/package.json +5 -5
  14. package/ui/dist/assets/{ContainerInspector-DgM0pTAx.js → ContainerInspector-Cu1tSN-o.js} +1 -1
  15. package/ui/dist/assets/EditorShell--V2ExYQ6.js +260 -0
  16. package/ui/dist/assets/ProjectLauncherScreen-Dmm6Z0mv.js +1 -0
  17. package/ui/dist/assets/ScenarioDataPanel-DjprZq2L.js +9 -0
  18. package/ui/dist/assets/{ScenarioDataPanelFullPage-BLqRCxQX.js → ScenarioDataPanelFullPage-BqMxWVKW.js} +1 -1
  19. package/ui/dist/assets/ScenarioRenderer-DqLVVMYS.js +21 -0
  20. package/ui/dist/assets/index-CjxWhkSy.css +1 -0
  21. package/ui/dist/assets/{index-DCHqRrwO.js → index-VuyqBbGJ.js} +2 -2
  22. package/ui/dist/assets/useServerIdentity-BdXy8TQv.js +1 -0
  23. package/ui/dist/index.html +2 -2
  24. package/ui/dist/assets/EditorShell-B7Q06uJ_.js +0 -252
  25. package/ui/dist/assets/ProjectLauncherScreen-BRrEr8Ng.js +0 -1
  26. package/ui/dist/assets/ScenarioDataPanel-BeQfa28g.js +0 -9
  27. package/ui/dist/assets/ScenarioRenderer-CIAxfHPh.js +0 -21
  28. package/ui/dist/assets/index-BygCiJSb.css +0 -1
  29. package/ui/dist/assets/useServerIdentity-B7rI0u3O.js +0 -1
@@ -784,6 +784,18 @@ function claudeAuthSeeded(mode) {
784
784
  // the server.js helper so callers don't have to thread one through.
785
785
  function _shq(s) { return `'${String(s).replace(/'/g, `'\\''`)}'`; }
786
786
 
787
+ // Assemble a `pkill -f` whose ERE is ANCHORED at the target's own executable:
788
+ // `^`, an optional directory prefix, then `exe`. Every sweep builder in this
789
+ // module routes through here so the anchor is structural rather than remembered
790
+ // — an unanchored `pkill -f` matches the FULL command line, which for the fleet
791
+ // dashboard's `sh -c '<add script>'` wrapper includes the script text itself.
792
+ // See the "Self-match-safe process sweeps" block below for the full failure
793
+ // mode. `argv` is an ERE fragment matched after the executable; escape any
794
+ // literal dots in it.
795
+ function _anchoredSweep({ exe, argv } = {}) {
796
+ return `pkill -f "^([^ ]*/)?${exe} ${argv}" 2>/dev/null`;
797
+ }
798
+
787
799
  /** Build a `docker exec … bash -c` sink that stages stdin to a same-directory
788
800
  * `.cytmp` sibling and only `mv`s it onto `target` when the staged file is
789
801
  * NON-EMPTY — exiting 1 (so the caller's `… || echo CY_DEGRADED` fires) and
@@ -978,13 +990,112 @@ function editorTunnelCmd({ gcloud, inst, zone, editorPort, n } = {}) {
978
990
  * from the editor reachability forward (`editorTunnelCmd`): a preview re-wire
979
991
  * pkills + respawns ONLY this process, leaving the editor :14199 forward — and
980
992
  * the reachability probe riding it — untouched. The preview local port is unique
981
- * per VM and never collides with the editor port, so the re-wire/destroy
982
- * `pkill -f "<previewPort>:127.0.0.1:"` targets exactly this process. Pure; no
983
- * I/O. */
993
+ * per VM and never collides with the editor port. Sweep it through
994
+ * `previewForwardSweepCmd` — the bare `pkill -f "<previewPort>:127.0.0.1:"` this
995
+ * comment used to call "targets exactly this process" did NOT: it also matched
996
+ * every `sh -c '<add script>'` wrapper carrying that literal. Pure; no I/O. */
984
997
  function previewTunnelCmd({ gcloud, inst, zone, previewPort, appPort, n } = {}) {
985
998
  return `nohup ${gcloud} compute ssh ${inst} --tunnel-through-iap --zone=${zone} -- -N -L ${previewPort}:127.0.0.1:${appPort} > /tmp/ssh-preview-vm-${n}.log 2>&1 &`;
986
999
  }
987
1000
 
1001
+ /* ── Self-match-safe process sweeps ─────────────────────────────────────────
1002
+ *
1003
+ * Every builder below emits a `pkill -f` whose match expression is ANCHORED at
1004
+ * the TARGET's executable — a leading `^`, an optional directory prefix, then
1005
+ * the program name (`ssh`, `node`, `cloudflared`). That anchor is the entire
1006
+ * point of these builders, not decoration.
1007
+ *
1008
+ * `pkill -f` matches the FULL command line. The fleet dashboard runs an Add as
1009
+ * `/bin/sh -c '<the entire add script text>'`, and that script text EMBEDS these
1010
+ * very sweep lines — so an unanchored pattern like `pkill -f
1011
+ * "14199:127.0.0.1:14199"` is a substring of the wrapper's own argv. It SIGTERMs
1012
+ * the wrapper that is running it, and every concurrent SIBLING add wrapper too.
1013
+ * The wrapper then dies from an uncaught signal, so its EXIT trap never writes
1014
+ * the `add-<n>.exit` marker that `fc.readExitMarker` / `fc.reattachVerdict` exist
1015
+ * to consume; `startJob`'s exec callback reports a red "Add failed" on a VM that
1016
+ * is fine; and the detached `cloud:up` it started — whose own argv does NOT carry
1017
+ * the pattern — is orphaned to init and keeps provisioning, after which
1018
+ * stranded-reconcile declares the VM half-provisioned and stacks a SECOND
1019
+ * `cloud:up` on top of it. That is the 2026-07-31 VM-3..8 batch, whose containers
1020
+ * were Up and answering /api/health 200 throughout.
1021
+ *
1022
+ * Excluding `$$` / `$PPID` does NOT fix this: the processes being wrongly killed
1023
+ * are SIBLINGS, not self or parent. The pattern itself must be incapable of
1024
+ * matching a `sh -c '<script>'` command line, and anchoring at the executable is
1025
+ * what guarantees that — a wrapper's argv always begins with the shell, never
1026
+ * with `ssh` / `node` / `cloudflared`.
1027
+ *
1028
+ * Same trap, same lesson as `npm/cloud.js` bootstrapStatusCommand (:1446) and
1029
+ * projectBootstrapStatusCommand (:1760), which document it explicitly ("the
1030
+ * status command's own argv contains the bootstrap path, so a `pgrep -f` on it
1031
+ * would match this very probe") and dodge it with a PID file + `kill -0`. A PID
1032
+ * file cannot replace THESE sweeps: they deliberately target STRAY processes left
1033
+ * by a prior add, a crashed watchdog respawn, or an earlier container generation
1034
+ * — processes this script never owned and holds no PID for. So the sweep stays
1035
+ * pattern-based; only the pattern's blast radius changes.
1036
+ *
1037
+ * Keep every sweep in this family behind one of these builders. Re-inlining a
1038
+ * bare `pkill -f` at a call site is exactly how the bug got in the first time. */
1039
+
1040
+ /** Sweep a stray EDITOR reachability forward — the `-L <localPort>:127.0.0.1:14199`
1041
+ * ssh process `editorTunnelCmd` opens.
1042
+ *
1043
+ * Targets the `ssh` CHILD, not the `gcloud compute ssh` python parent. The child
1044
+ * is what binds the local listening socket, so killing it is what actually
1045
+ * releases the port; the parent is only waiting on it and exits on its own once
1046
+ * it goes. Only the child's argv starts with `ssh`, which is also what makes the
1047
+ * anchor safe. Pure; no I/O. */
1048
+ function editorForwardSweepCmd({ localPort } = {}) {
1049
+ return _anchoredSweep({ exe: "ssh", argv: `.*-L ${localPort}:127\\.0\\.0\\.1:14199` });
1050
+ }
1051
+
1052
+ /** Sweep a stray LIVE-PREVIEW forward — the `-L <localPort>:127.0.0.1:<appPort>`
1053
+ * ssh process `previewTunnelCmd` opens. The remote port is left open because the
1054
+ * app's dev-server port legitimately drifts; the per-VM preview local port is the
1055
+ * identifying half and never collides with the editor port. Same ssh-child
1056
+ * targeting as `editorForwardSweepCmd`. Pure; no I/O. */
1057
+ function previewForwardSweepCmd({ localPort } = {}) {
1058
+ return _anchoredSweep({ exe: "ssh", argv: `.*-L ${localPort}:127\\.0\\.0\\.1:` });
1059
+ }
1060
+
1061
+ /** Sweep a wedged `cloud:up` provision for one instance.
1062
+ *
1063
+ * Targets the `node npm/cloud.js up --instance-name <inst>` process, NOT the
1064
+ * `npm run cloud:up` parent — call sites already hold the npm child's PID and
1065
+ * `kill` it directly; this reaps the node grandchild that PID does not cover.
1066
+ * `--instance-name` is the first pair `cloudUpArgs` emits, so the literal stays
1067
+ * adjacent to `up`. Pure; no I/O. */
1068
+ function cloudUpSweepCmd({ inst } = {}) {
1069
+ return _anchoredSweep({ exe: "node", argv: `.*cloud\\.js up --instance-name ${inst}` });
1070
+ }
1071
+
1072
+ /** Sweep the cloudflared quick-tunnel fronting a VM's editor port.
1073
+ *
1074
+ * Anchored for the same reason as its siblings, with one extra bite: this sweep
1075
+ * runs inside a `sh -c` compound built by `exec()`, so unanchored it matched its
1076
+ * OWN parent shell — killing the compound before the editor/preview sweeps that
1077
+ * follow it on the same line ever ran. Pure; no I/O. */
1078
+ function cloudflaredTunnelSweepCmd({ localPort } = {}) {
1079
+ return _anchoredSweep({ exe: "cloudflared", argv: `tunnel --url http://localhost:${localPort}` });
1080
+ }
1081
+
1082
+ /** Build the destroy-time local reap compound for one VM: free the editor port,
1083
+ * then sweep the cloudflared quick-tunnel and BOTH split ssh forwards.
1084
+ *
1085
+ * Lives here rather than inline in `cleanLocalVmArtifacts` because the ORDERING
1086
+ * is load-bearing and was previously untestable: the whole compound runs as one
1087
+ * `sh -c`, so the unanchored cloudflared sweep used to match that shell's own
1088
+ * argv and kill it BEFORE the two forward sweeps behind it ever ran — meaning a
1089
+ * destroy silently orphaned both forwards. Pure; no I/O. */
1090
+ function localVmReapCmd({ port, previewPort } = {}) {
1091
+ return [
1092
+ `lsof -ti:${port} 2>/dev/null | xargs -r kill`,
1093
+ cloudflaredTunnelSweepCmd({ localPort: port }),
1094
+ editorForwardSweepCmd({ localPort: port }),
1095
+ previewForwardSweepCmd({ localPort: previewPort }),
1096
+ ].join("; ");
1097
+ }
1098
+
988
1099
  /** Build the shell snippet the Add script runs to AWAIT cloud:up's clean exit at
989
1100
  * container-healthy instead of reaping it mid-flight.
990
1101
  *
@@ -1009,7 +1120,7 @@ function awaitWiringCmd({ inst, deadlineSec = 180, pidVar = "UP_PID" } = {}) {
1009
1120
  `while kill -0 $${pidVar} 2>/dev/null; do`,
1010
1121
  ` if [ "$__cy_wiring_waited" -ge ${deadlineSec} ]; then`,
1011
1122
  ` echo "WARN cloud:up still running after ${deadlineSec}s (wedged before the container-healthy early return) — reaping it (the dashboard self-heal will converge any half-wired backend)"`,
1012
- ` kill $${pidVar} 2>/dev/null; pkill -f "cloud.js up --instance-name ${inst}" 2>/dev/null; break`,
1123
+ ` kill $${pidVar} 2>/dev/null; ${cloudUpSweepCmd({ inst })}; break`,
1013
1124
  ` fi`,
1014
1125
  ` sleep 5; __cy_wiring_waited=$((__cy_wiring_waited + 5))`,
1015
1126
  `done`,
@@ -1097,6 +1208,11 @@ module.exports = {
1097
1208
  decideStartJob,
1098
1209
  editorTunnelCmd,
1099
1210
  previewTunnelCmd,
1211
+ editorForwardSweepCmd,
1212
+ previewForwardSweepCmd,
1213
+ cloudUpSweepCmd,
1214
+ cloudflaredTunnelSweepCmd,
1215
+ localVmReapCmd,
1100
1216
  awaitWiringCmd,
1101
1217
  getAuthRepoUrl,
1102
1218
  interpretLsRemote,
@@ -191,14 +191,40 @@ const {
191
191
  // inject it here from the on-box 0600 token file.
192
192
  const SESSION_COOKIE = "cy_session";
193
193
 
194
+ // The loopback names the editor can be addressed by. A cookie is scoped by
195
+ // HOST, and the jar does NOT treat these as interchangeable: a cookie stored for
196
+ // `localhost` is simply not sent to `127.0.0.1`. That matters because the two
197
+ // token-gated capture routes resolve their origin differently — the harness
198
+ // route via `resolveHarnessOrigin()` (typically `localhost`), the preview-proxy
199
+ // route via `PROXY_CAPTURE_LOOPBACK` in handlers.rs, which is deliberately
200
+ // IPv4-pinned to `127.0.0.1` so it matches the forwarder's own pinning. Scoping
201
+ // the cookie to `localhost` alone therefore authenticated the harness route and
202
+ // left every `/__codeyam_preview` capture with no credential, so `preview-verify`
203
+ // / `preview-interact` / `preview-flow` all 401'd on a non-loopback bind.
204
+ // Emitting one cookie per alias is the fix: same token, same on-box editor,
205
+ // whichever name the capture URL happens to use.
206
+ const LOOPBACK_COOKIE_DOMAINS = ["localhost", "127.0.0.1"];
207
+
208
+ // Extract the host from an origin string, or null when it is unparseable.
209
+ function originHost(origin) {
210
+ try {
211
+ return new URL(origin).hostname;
212
+ } catch (_) {
213
+ return null;
214
+ }
215
+ }
216
+
194
217
  // Build the Playwright cookie array that authenticates the capture context to
195
218
  // the editor's token-gated control-API. Reads the on-box `.codeyam/session-token`
196
- // (0600) and scopes a `cy_session` cookie to `localhost` (localhost cookies are
197
- // port-agnostic, so the same cookie covers the harness origin on the control
198
- // port and any `/api` call on the app-proxy port). Returns `[]` — a no-op — when
199
- // there is no token file (a loopback bind that never persisted one) or no
200
- // resolvable harness origin, so a laptop capture is completely unaffected.
201
- // `deps` is injectable so the builder is unit-testable without disk.
219
+ // (0600) and emits a `cy_session` cookie for every host the capture might address
220
+ // the editor by (see `LOOPBACK_COOKIE_DOMAINS`); cookies are port-agnostic, so
221
+ // one per host covers the harness origin on the control port, the preview-proxy
222
+ // route, and any `/api` call on the app-proxy port. A non-loopback harness origin
223
+ // (a cloud tunnel domain) additionally gets its own host, since no loopback alias
224
+ // would match it. Returns `[]` — a no-op — when there is no token file (a
225
+ // loopback bind that never persisted one) or no resolvable harness origin, so a
226
+ // laptop capture is completely unaffected. `deps` is injectable so the builder is
227
+ // unit-testable without disk.
202
228
  function buildSessionTokenCookies({
203
229
  readTokenFile = () => {
204
230
  const p = path.join(process.cwd(), ".codeyam", "session-token");
@@ -209,16 +235,19 @@ function buildSessionTokenCookies({
209
235
  try {
210
236
  const token = readTokenFile();
211
237
  if (!token || !harnessOrigin) return [];
212
- return [
213
- {
214
- name: SESSION_COOKIE,
215
- value: token,
216
- domain: "localhost",
217
- path: "/",
218
- httpOnly: true,
219
- sameSite: "Lax",
220
- },
221
- ];
238
+ const host = originHost(harnessOrigin);
239
+ const domains = [...LOOPBACK_COOKIE_DOMAINS];
240
+ // A tunnelled/cloud harness origin is not a loopback alias, so it needs its
241
+ // own entry or the harness navigation goes out uncredentialed.
242
+ if (host && !domains.includes(host)) domains.push(host);
243
+ return domains.map((domain) => ({
244
+ name: SESSION_COOKIE,
245
+ value: token,
246
+ domain,
247
+ path: "/",
248
+ httpOnly: true,
249
+ sameSite: "Lax",
250
+ }));
222
251
  } catch (_) {
223
252
  // A missing/unreadable token file must never break capture on a loopback
224
253
  // bind where the token isn't required anyway — degrade to no cookie.
@@ -817,9 +846,14 @@ async function runScenarioCheck(
817
846
  config,
818
847
  { preflight = assertAppPortReachable, harnessOrigin } = {},
819
848
  ) {
820
- const resolvedHarnessOrigin =
821
- harnessOrigin !== undefined ? harnessOrigin : resolveHarnessOrigin();
822
849
  const { url, outputPath, width, height, httpMocks = {} } = config;
850
+ // The harness host mirrors the capture target's host so the framed load stays
851
+ // SAME-SITE — see `resolveHarnessOrigin`. A cross-site frame withholds the
852
+ // SameSite=Lax `cy_session` cookie and every token-gated route 401s.
853
+ const resolvedHarnessOrigin =
854
+ harnessOrigin !== undefined
855
+ ? harnessOrigin
856
+ : resolveHarnessOrigin({ targetUrl: url });
823
857
  // Per-scenario capture-check allowances (see `CaptureAllowances` /
824
858
  // `ScenarioDefinition` on the Rust side). Default false so the guards keep
825
859
  // their strict behavior for every scenario that does not opt in.
@@ -146,20 +146,54 @@ function defaultReadServerState() {
146
146
  return JSON.parse(fs.readFileSync(statePath, "utf8"));
147
147
  }
148
148
 
149
- // Resolve the `localhost` origin that serves the iframe-harness route. The
150
- // harness is mounted on the editor's control-api listener, whose port is
151
- // recorded in `.codeyam/server-state.json` as `controlPort` (the same file the
152
- // top-level loader already reads for `appPort`). Returns
153
- // `http://localhost:<controlPort>` — a secure context the nested iframe
154
- // inherits — or null when the state file is missing/unreadable, in which case
155
- // the caller falls back to the legacy in-page `setContent` harness.
156
- // `readStateFile` is injectable so the resolver is unit-testable without disk.
157
- function resolveHarnessOrigin({ readStateFile = defaultReadServerState } = {}) {
149
+ // Resolve the loopback origin that serves the iframe-harness route. The harness
150
+ // is mounted on the editor's control-api listener, whose port is recorded in
151
+ // `.codeyam/server-state.json` as `controlPort` (the same file the top-level
152
+ // loader already reads for `appPort`). Returns `http://127.0.0.1:<controlPort>`
153
+ // — a secure context the nested iframe inherits, exactly as `localhost` is — or
154
+ // null when the state file is missing/unreadable, in which case the caller falls
155
+ // back to the legacy in-page `setContent` harness. `readStateFile` is injectable
156
+ // so the resolver is unit-testable without disk.
157
+ //
158
+ // The HOST is taken from `targetUrl` — the URL the iframe will load — and only
159
+ // the port comes from server-state. That mirroring is load-bearing, because the
160
+ // two capture modes address the editor by different loopback spellings:
161
+ // `/__codeyam_preview` captures are pinned to `127.0.0.1` (PROXY_CAPTURE_LOOPBACK
162
+ // in handlers.rs, matching the forwarder's own pinning) while direct app-port
163
+ // captures use `localhost`. `localhost` and `127.0.0.1` are DIFFERENT sites to
164
+ // the cookie jar, so whenever the harness host and the iframe host disagree the
165
+ // nested load is cross-site — and the `cy_session` cookie is `SameSite=Lax`,
166
+ // which rides top-level navigations only. It is therefore withheld from the
167
+ // iframe request (and from the `/api/*` calls the framed page makes), and the
168
+ // token-gated routes answer 401 on a non-loopback bind.
169
+ //
170
+ // Hardcoding EITHER spelling only moves the failure between the two modes:
171
+ // `localhost` 401s every `/__codeyam_preview` capture, `127.0.0.1` 401s the
172
+ // framed page's own `/api/scenarios` + `/api/render-environment` calls. Raising
173
+ // the cookie to `SameSite=None` fixes neither — Chromium rejects `None` without
174
+ // `Secure`, and these origins are plain http. Mirroring the target's host is what
175
+ // keeps the harness same-site in both modes, which is also the same-origin model
176
+ // the `/__codeyam_preview` subpath proxy exists to provide.
177
+ //
178
+ // `targetUrl` omitted or unparseable falls back to `127.0.0.1`, the spelling the
179
+ // proxy-route capture (the token-gated one) uses.
180
+ function resolveHarnessOrigin({
181
+ readStateFile = defaultReadServerState,
182
+ targetUrl = null,
183
+ } = {}) {
158
184
  try {
159
185
  const state = readStateFile();
160
186
  const port = state && state.controlPort;
161
187
  if (typeof port === "number" && port > 0) {
162
- return `http://localhost:${port}`;
188
+ let host = "127.0.0.1";
189
+ if (targetUrl) {
190
+ try {
191
+ host = new URL(targetUrl).hostname || host;
192
+ } catch (_) {
193
+ /* unparseable target — keep the proxy-route default */
194
+ }
195
+ }
196
+ return `http://${host}:${port}`;
163
197
  }
164
198
  } catch (_) {
165
199
  /* missing/unreadable state — fall back to setContent */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeyam-editor/codeyam-editor",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Language-agnostic managed execution sandbox for scenario-driven development",
5
5
  "bin": {
6
6
  "codeyam-editor": "./npm/cli.js"
@@ -9,10 +9,10 @@
9
9
  "playwright": "^1.58.2"
10
10
  },
11
11
  "optionalDependencies": {
12
- "@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.6",
13
- "@codeyam-editor/codeyam-editor-darwin-x64": "0.1.6",
14
- "@codeyam-editor/codeyam-editor-linux-x64": "0.1.6",
15
- "@codeyam-editor/codeyam-editor-win32-x64": "0.1.6"
12
+ "@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.7",
13
+ "@codeyam-editor/codeyam-editor-darwin-x64": "0.1.7",
14
+ "@codeyam-editor/codeyam-editor-linux-x64": "0.1.7",
15
+ "@codeyam-editor/codeyam-editor-win32-x64": "0.1.7"
16
16
  },
17
17
  "keywords": [
18
18
  "codeyam",
@@ -1,2 +1,2 @@
1
- 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(`
1
+ 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-VuyqBbGJ.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(`
2
2
  `)})}),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};