@codeyam-editor/codeyam-editor 0.1.8 → 0.1.10

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 (41) hide show
  1. package/npm/cloud.js +377 -21
  2. package/npm/editor-dev.js +24 -2
  3. package/npm/editor.js +15 -5
  4. package/npm/fleet-add-failure.js +355 -21
  5. package/npm/fleet-auth-account.js +61 -0
  6. package/npm/fleet-auth.js +69 -1
  7. package/npm/fleet-branch.js +124 -1
  8. package/npm/fleet-build-data.js +12 -1
  9. package/npm/fleet-cleanup.js +84 -3
  10. package/npm/fleet-datastore-health.js +107 -0
  11. package/npm/fleet-public-url.js +81 -12
  12. package/npm/fleet-reconcile.js +46 -11
  13. package/npm/fleet-revision.js +108 -0
  14. package/npm/fleet-run-setup.js +66 -0
  15. package/npm/fleet-session-activity.js +162 -0
  16. package/npm/fleet-vm-readiness.js +57 -16
  17. package/npm/group-bounded-spawn.js +111 -0
  18. package/npm/launch-config.js +216 -23
  19. package/npm/orphan-ssh-reaper.js +81 -0
  20. package/npm/scenario-check.js +697 -34
  21. package/npm/scenario-interactivity.js +477 -23
  22. package/npm/scenario-issues.js +61 -0
  23. package/npm/scenario-playwright.js +174 -20
  24. package/npm/utils.js +262 -22
  25. package/package.json +5 -5
  26. package/ui/dist/assets/{ContainerInspector-DSVZvEkB.js → ContainerInspector-DiN91foX.js} +1 -1
  27. package/ui/dist/assets/EditorShell-BEIdHnHd.css +1 -0
  28. package/ui/dist/assets/EditorShell-CPV5vhjo.js +330 -0
  29. package/ui/dist/assets/ScenarioDataPanel-DHAHyraq.js +18 -0
  30. package/ui/dist/assets/{ScenarioDataPanelFullPage-Cyk6efiI.js → ScenarioDataPanelFullPage-CHIWip3n.js} +1 -1
  31. package/ui/dist/assets/ScenarioRenderer-D9a91iwS.js +21 -0
  32. package/ui/dist/assets/index--cE0hUJw.css +1 -0
  33. package/ui/dist/assets/{index-BPLKgwon.js → index-sW8wcg7v.js} +9 -9
  34. package/ui/dist/index.html +2 -2
  35. package/ui/dist/preview-subdir-demo/index.html +62 -0
  36. package/ui/dist/preview-subdir-demo/sibling.html +48 -0
  37. package/ui/dist/assets/EditorShell-DnXdHrar.js +0 -256
  38. package/ui/dist/assets/EditorShell-FvbXyqqD.css +0 -1
  39. package/ui/dist/assets/ScenarioDataPanel-6qJE-0lA.js +0 -15
  40. package/ui/dist/assets/ScenarioRenderer-Uyt54vHI.js +0 -21
  41. package/ui/dist/assets/index-DKpgJLo3.css +0 -1
package/npm/utils.js CHANGED
@@ -5,7 +5,23 @@ const fs = require("fs");
5
5
  const readline = require("readline");
6
6
 
7
7
  const rootDir = path.resolve(__dirname, "..");
8
- const serverStatePath = path.join(rootDir, ".codeyam", "server-state.json");
8
+
9
+ /**
10
+ * Path to the server-state file for `projectDir`.
11
+ *
12
+ * The editor server writes its state into the PROJECT it serves, not into the
13
+ * editor repo — so this must be resolved against the target project. It was
14
+ * previously a module-level const bound to `rootDir`, which made
15
+ * `readServerState` return `null` for every external-project launch and left
16
+ * the pid-based recovery in `stopServer` dead in exactly the configuration
17
+ * `codeyam-editor-dev` exists to serve.
18
+ *
19
+ * Defaults to `process.cwd()` because every in-repo caller already runs from
20
+ * the project root; external-project callers must pass their `projectDir`.
21
+ */
22
+ function serverStatePathFor(projectDir = process.cwd()) {
23
+ return path.join(projectDir, ".codeyam", "server-state.json");
24
+ }
9
25
 
10
26
  /**
11
27
  * Map (process.platform, process.arch) → the platform sub-package that
@@ -459,6 +475,56 @@ function resolveWrappedAppPort(merged, envValue, fallback) {
459
475
  return resolveLauncherPort(envValue, mergedValue, fallback);
460
476
  }
461
477
 
478
+ /** True for a value usable as a TCP port: an integer in 1..=65535. */
479
+ function isUsablePort(value) {
480
+ return Number.isInteger(value) && value > 0 && value <= 65535;
481
+ }
482
+
483
+ /**
484
+ * Resolve the control port a RUNNING server for `projectDir` is actually on.
485
+ *
486
+ * Mirrors `resolve_control_port` in
487
+ * `crates/codeyam-editor/src/commands/editor/control_port.rs`:
488
+ * `server-state.json` > `CODEYAM_CONTROL_PORT` > the config default. The
489
+ * editor server runs on a dynamic port whenever the Project Launcher or the
490
+ * desktop supervisor started it, and `editor.json`'s `proxy.controlPort` is
491
+ * only the static default — so `server-state.json` is the only reliable
492
+ * discriminator. The npm launchers used the INVERSE (config only, state file
493
+ * never consulted), which is why a `--restart` could target a port nothing was
494
+ * on while the live server sat on another.
495
+ *
496
+ * This resolves the port to SEARCH for, never the port to bind: the launcher
497
+ * deliberately binds the editor repo's own control port (see the comment at
498
+ * the `SERVER_PORT` resolution in `editor-dev.js`).
499
+ */
500
+ function resolveRunningControlPort(projectDir = process.cwd(), configPort) {
501
+ const state = readServerState(projectDir);
502
+ if (state && isUsablePort(state.controlPort)) return state.controlPort;
503
+
504
+ const envValue = process.env.CODEYAM_CONTROL_PORT;
505
+ if (envValue !== undefined && envValue !== null && String(envValue).trim() !== "") {
506
+ const parsed = parseInt(String(envValue).trim(), 10);
507
+ if (isUsablePort(parsed)) return parsed;
508
+ }
509
+
510
+ return configPort;
511
+ }
512
+
513
+ /**
514
+ * Resolve the proxy HTTP port the server will bind for `projectDir`.
515
+ *
516
+ * Mirrors `resolve_proxy_http_port` in
517
+ * `crates/codeyam-editor/src/commands/start.rs`: `CODEYAM_PROXY_HTTP_PORT` >
518
+ * `proxy.httpPort` > 14100 (`default_http_port` in
519
+ * `crates/types/src/config.rs`). The start path binds this address
520
+ * unconditionally, so it is the port a second server actually collides on —
521
+ * the resource the control-port classification never looked at.
522
+ */
523
+ function resolveProxyHttpPort(merged, envValue, fallback = 14100) {
524
+ const configured = merged && merged.proxy && merged.proxy.httpPort;
525
+ return resolveLauncherPort(envValue, configured, fallback);
526
+ }
527
+
462
528
  /** Try to connect to a specific host:port. Returns true if something is listening. */
463
529
  function tryConnect(port, host) {
464
530
  return new Promise((resolve) => {
@@ -502,17 +568,17 @@ async function waitForPortToClose(port, timeoutMs = 10000, intervalMs = 200) {
502
568
  return false;
503
569
  }
504
570
 
505
- function readServerState() {
571
+ function readServerState(projectDir = process.cwd()) {
506
572
  try {
507
- return JSON.parse(fs.readFileSync(serverStatePath, "utf8"));
573
+ return JSON.parse(fs.readFileSync(serverStatePathFor(projectDir), "utf8"));
508
574
  } catch {
509
575
  return null;
510
576
  }
511
577
  }
512
578
 
513
- function clearServerState() {
579
+ function clearServerState(projectDir = process.cwd()) {
514
580
  try {
515
- fs.unlinkSync(serverStatePath);
581
+ fs.unlinkSync(serverStatePathFor(projectDir));
516
582
  } catch {}
517
583
  }
518
584
 
@@ -626,6 +692,100 @@ function formatCrossProjectError(port, holder, verb) {
626
692
  );
627
693
  }
628
694
 
695
+ /**
696
+ * Build the "the proxy port this server must bind is already taken" error
697
+ * string. Lives next to the other `format*Error` builders so the wording is
698
+ * unit-testable without a running server. Names the port, the pid holding it,
699
+ * and the config key to change — the three things the old failure mode made
700
+ * the user dig out of `.codeyam/logs/editor-server.out.log` by hand.
701
+ */
702
+ function formatProxyPortConflictError(httpPort, pids = []) {
703
+ const pidNote = pids.length > 0 ? ` (pid ${pids.join(", ")})` : "";
704
+ return (
705
+ `Port ${httpPort} is already in use${pidNote}, and the codeyam-editor ` +
706
+ `server binds it at startup — spawning now would fail with EADDRINUSE ` +
707
+ `and leave nothing listening.\n` +
708
+ `\n` +
709
+ `Free that port, or change httpPort in .codeyam/editor.local.json, e.g.:\n` +
710
+ ` codeyam-editor editor config-override proxy.httpPort ${httpPort + 100}`
711
+ );
712
+ }
713
+
714
+ /**
715
+ * Make sure the proxy HTTP port is free before a spawn that would bind it.
716
+ *
717
+ * The proxy port — not the control port — is the resource that actually
718
+ * conflicts: two servers for the same project legitimately resolve DIFFERENT
719
+ * control ports (the npm wrappers use the editor repo's config, the Rust binary
720
+ * uses the project's own), but both bind the project's `proxy.httpPort`. So a
721
+ * control-port classification can report "free" while the spawn is already
722
+ * doomed, which is exactly how a failed restart came to look like a successful
723
+ * one.
724
+ *
725
+ * Ownership is decided on the control port named by the project's own
726
+ * `server-state.json`, never by probing the identity endpoint through the proxy
727
+ * port itself: the proxy forwards to the wrapped app, so a probe there reports
728
+ * whatever the app answers and would misclassify this project's own server as
729
+ * foreign. Teardown likewise goes through the control port, where the shutdown
730
+ * endpoint lives.
731
+ *
732
+ * Returns `{ kind: "free" }`, `{ kind: "cleared" }` (a stale same-project server
733
+ * was stopped), or `{ kind: "conflict", pids }` — the caller owns the policy.
734
+ * Effects are injected so this is testable without a live server.
735
+ */
736
+ async function ensureProxyPortAvailable(
737
+ httpPort,
738
+ projectDir = process.cwd(),
739
+ { classify = classifyPortHolder, stop = stopServer, isInUse = isPortInUse } = {},
740
+ ) {
741
+ if (!isUsablePort(httpPort) || !(await isInUse(httpPort))) {
742
+ return { kind: "free" };
743
+ }
744
+
745
+ const state = readServerState(projectDir);
746
+ const statePort = state && isUsablePort(state.controlPort) ? state.controlPort : null;
747
+ if (statePort !== null) {
748
+ const holder = await classify(statePort, projectDir);
749
+ if (holder.kind === "same-project") {
750
+ console.error(
751
+ `Port ${httpPort} is held by this project's own server on control ` +
752
+ `port ${statePort}; stopping it before starting a fresh one...`,
753
+ );
754
+ await stop(statePort, projectDir);
755
+ if (await waitForPortToClose(httpPort, 5000, 200)) {
756
+ return { kind: "cleared" };
757
+ }
758
+ }
759
+ }
760
+
761
+ return { kind: "conflict", pids: findListeningPids(httpPort) };
762
+ }
763
+
764
+ /**
765
+ * Build the "the launcher is not going to print a URL for a server that never
766
+ * came up" message, including the tail of the server output log.
767
+ *
768
+ * `tail` is the already-read log tail (see `readServerOutputLogTail`) or `null`
769
+ * when there was nothing readable — passed in rather than read here so the
770
+ * wording is testable without a filesystem, matching the other `format*Error`
771
+ * builders. The diagnostic was never missing from that log; it was written to a
772
+ * file nobody was told to read, which is why the tail is inlined into the
773
+ * message rather than merely pointed at.
774
+ */
775
+ function formatLaunchFailureError(port, projectDir, tail = null) {
776
+ const logPath = path.join(projectDir, ".codeyam", "logs", "editor-server.out.log");
777
+ const head =
778
+ `Editor server is not listening on port ${port} — not printing a URL ` +
779
+ `that would refuse the connection.`;
780
+ if (tail === null) {
781
+ return (
782
+ `${head}\n\nNo readable ${logPath}; also check ` +
783
+ `${path.join(projectDir, ".codeyam", "logs", "editor-server.log")}.`
784
+ );
785
+ }
786
+ return `${head}\n\n--- tail of ${logPath} ---\n${tail}\n--- end of log tail ---`;
787
+ }
788
+
629
789
  /**
630
790
  * Build the "server never bound the port" failure message, shown only after
631
791
  * the boot budget AND one automatic retry have both been exhausted. Pure
@@ -833,6 +993,47 @@ function openServerOutputLog(cwd) {
833
993
  }
834
994
  }
835
995
 
996
+ /**
997
+ * Last `lines` non-empty-trailing lines of the launcher-managed server output
998
+ * log for `projectDir`, or `null` when there is nothing readable there.
999
+ *
1000
+ * The diagnostic text for a failed launch was never missing — the exact
1001
+ * `codeyam-editor cannot bind 127.0.0.1:<port>` line sat in this file the whole
1002
+ * time. It was written to a file nobody was told to read, so the launcher
1003
+ * surfaces the tail itself rather than printing a URL and exiting 0.
1004
+ *
1005
+ * Reads at most the trailing 64 KiB so a long-lived append-only log never costs
1006
+ * a full file read. Best-effort by design: a missing or unreadable log degrades
1007
+ * to `null`, never to a throw on the failure path.
1008
+ */
1009
+ function readServerOutputLogTail(projectDir = process.cwd(), lines = 40) {
1010
+ const MAX_TAIL_BYTES = 64 * 1024;
1011
+ let fd = null;
1012
+ try {
1013
+ const logPath = path.join(projectDir, ".codeyam", "logs", "editor-server.out.log");
1014
+ fd = fs.openSync(logPath, "r");
1015
+ const size = fs.fstatSync(fd).size;
1016
+ const length = Math.min(size, MAX_TAIL_BYTES);
1017
+ if (length === 0) return null;
1018
+ const buf = Buffer.alloc(length);
1019
+ fs.readSync(fd, buf, 0, length, size - length);
1020
+ const all = buf.toString("utf8").split("\n");
1021
+ while (all.length > 0 && all[all.length - 1].trim() === "") all.pop();
1022
+ if (all.length === 0) return null;
1023
+ return all.slice(-lines).join("\n");
1024
+ } catch {
1025
+ return null;
1026
+ } finally {
1027
+ if (fd !== null) {
1028
+ try {
1029
+ fs.closeSync(fd);
1030
+ } catch {
1031
+ /* best-effort close on a diagnostic-only read */
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+
836
1037
  /**
837
1038
  * Format one launcher-teardown-signal record for
838
1039
  * `.codeyam/logs/launcher-signals.log`. Pure: every input is passed in, so the
@@ -965,23 +1166,23 @@ function findListeningPids(port, runLsof = defaultRunLsof, sleep = sleepSync) {
965
1166
  }
966
1167
 
967
1168
  /** Stop the Rust backend server if it is running. */
968
- async function stopServer(port = 14199) {
1169
+ async function stopServer(port = 14199, projectDir = process.cwd()) {
969
1170
  if (!(await isPortInUse(port))) {
970
- clearServerState();
1171
+ clearServerState(projectDir);
971
1172
  return false;
972
1173
  }
973
1174
 
974
1175
  if (await requestServerShutdown(port)) {
975
1176
  if (await waitForPortToClose(port, 10000, 200)) {
976
- clearServerState();
1177
+ clearServerState(projectDir);
977
1178
  return true;
978
1179
  }
979
1180
  }
980
1181
 
981
- const state = readServerState();
1182
+ const state = readServerState(projectDir);
982
1183
  if (state && Number.isInteger(state.pid) && tryKillPid(state.pid)) {
983
1184
  if (await waitForPortToClose(port, 5000, 200)) {
984
- clearServerState();
1185
+ clearServerState(projectDir);
985
1186
  return true;
986
1187
  }
987
1188
  }
@@ -991,20 +1192,37 @@ async function stopServer(port = 14199) {
991
1192
  }
992
1193
 
993
1194
  if (await waitForPortToClose(port, 5000, 200)) {
994
- clearServerState();
1195
+ clearServerState(projectDir);
995
1196
  return true;
996
1197
  }
997
1198
 
998
1199
  throw new Error(`Server on port ${port} did not stop cleanly`);
999
1200
  }
1000
1201
 
1001
- /** Stop any existing server on the port, then start a fresh one. */
1002
- async function restartServer(port = 14199) {
1003
- if (await isPortInUse(port)) {
1004
- console.error(`Stopping existing server on port ${port}...`);
1005
- await stopServer(port);
1202
+ /**
1203
+ * Stop any existing server for this project, then start a fresh one on `port`.
1204
+ *
1205
+ * `port` is the port to BIND (owned by the editor repo's merged config); the
1206
+ * port to TEAR DOWN is resolved separately via `resolveRunningControlPort`,
1207
+ * because a server started outside the npm wrapper records a different, live
1208
+ * control port in the project's `server-state.json`. Gating teardown on `port`
1209
+ * alone is what let a stale server survive a restart and kill the relaunch with
1210
+ * EADDRINUSE on the proxy port. Both are torn down (deduped) so the restart's
1211
+ * historical guarantee — nothing left on the port we are about to bind — holds
1212
+ * whichever port the live server turned out to be on.
1213
+ */
1214
+ async function restartServer(port = 14199, projectDir = process.cwd()) {
1215
+ const runningPort = resolveRunningControlPort(projectDir, port);
1216
+ const seen = new Set();
1217
+ for (const candidate of [runningPort, port]) {
1218
+ if (!isUsablePort(candidate) || seen.has(candidate)) continue;
1219
+ seen.add(candidate);
1220
+ if (await isPortInUse(candidate)) {
1221
+ console.error(`Stopping existing server on port ${candidate}...`);
1222
+ await stopServer(candidate, projectDir);
1223
+ }
1006
1224
  }
1007
- return ensureServer(port);
1225
+ return ensureServer(port, projectDir);
1008
1226
  }
1009
1227
 
1010
1228
  /**
@@ -1016,8 +1234,8 @@ async function restartServer(port = 14199) {
1016
1234
  * mismatch — silently choosing a different port would just relocate the
1017
1235
  * surprise.
1018
1236
  */
1019
- async function ensureServer(port = 14199) {
1020
- const holder = await classifyPortHolder(port);
1237
+ async function ensureServer(port = 14199, projectDir = process.cwd()) {
1238
+ const holder = await classifyPortHolder(port, projectDir);
1021
1239
  switch (holder.kind) {
1022
1240
  case "foreign":
1023
1241
  console.error(formatForeignListenerError(port));
@@ -1056,6 +1274,21 @@ async function ensureServer(port = 14199) {
1056
1274
  break;
1057
1275
  }
1058
1276
 
1277
+ // The control port is free (or was just taken over), but that is not the port
1278
+ // the spawn is most likely to die on. `start.rs` binds `proxy.httpPort`
1279
+ // unconditionally, so a holder there is a guaranteed EADDRINUSE — knowable
1280
+ // with one probe here, and previously discovered only by reading a log after
1281
+ // a silent failure.
1282
+ const proxyHttpPort = resolveProxyHttpPort(
1283
+ readMergedEditorConfig(projectDir),
1284
+ process.env.CODEYAM_PROXY_HTTP_PORT,
1285
+ );
1286
+ const proxyPort = await ensureProxyPortAvailable(proxyHttpPort, projectDir);
1287
+ if (proxyPort.kind === "conflict") {
1288
+ console.error(formatProxyPortConflictError(proxyHttpPort, proxyPort.pids));
1289
+ process.exit(1);
1290
+ }
1291
+
1059
1292
  const binary = ensureBinary();
1060
1293
  const startTimeoutMs = resolveStartTimeoutMs();
1061
1294
 
@@ -1075,12 +1308,12 @@ async function ensureServer(port = 14199) {
1075
1308
  // editor-server.log). `unref()` keeps the detached child from pinning the
1076
1309
  // launcher's event loop alive on its own.
1077
1310
  const spawnAndAwait = async (timeoutMs) => {
1078
- const logFd = openServerOutputLog(process.cwd());
1311
+ const logFd = openServerOutputLog(projectDir);
1079
1312
  const child = spawn(
1080
1313
  binary,
1081
1314
  ["start", "--no-open", "--port", String(port)],
1082
1315
  buildServerSpawnOptions({
1083
- cwd: process.cwd(),
1316
+ cwd: projectDir,
1084
1317
  env: serverSpawnEnv(process.env, { devCheckout: isDevCheckout() }),
1085
1318
  logFd,
1086
1319
  }),
@@ -1215,7 +1448,7 @@ async function awaitServerReadyOrChildExit(child, port, waitForPortFn = waitForP
1215
1448
 
1216
1449
  module.exports = {
1217
1450
  rootDir,
1218
- serverStatePath,
1451
+ serverStatePathFor,
1219
1452
  binaryName,
1220
1453
  brokerBinaryName,
1221
1454
  platformPackageInfo,
@@ -1241,6 +1474,9 @@ module.exports = {
1241
1474
  classifyPortHolder,
1242
1475
  formatForeignListenerError,
1243
1476
  formatCrossProjectError,
1477
+ formatProxyPortConflictError,
1478
+ formatLaunchFailureError,
1479
+ ensureProxyPortAvailable,
1244
1480
  formatServerStartTimeoutError,
1245
1481
  resolveStartTimeoutMs,
1246
1482
  tryKillPid,
@@ -1264,4 +1500,8 @@ module.exports = {
1264
1500
  readMergedEditorConfig,
1265
1501
  resolveLauncherPort,
1266
1502
  resolveWrappedAppPort,
1503
+ resolveRunningControlPort,
1504
+ resolveProxyHttpPort,
1505
+ isUsablePort,
1506
+ readServerOutputLogTail,
1267
1507
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeyam-editor/codeyam-editor",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
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.8",
13
- "@codeyam-editor/codeyam-editor-darwin-x64": "0.1.8",
14
- "@codeyam-editor/codeyam-editor-linux-x64": "0.1.8",
15
- "@codeyam-editor/codeyam-editor-win32-x64": "0.1.8"
12
+ "@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.10",
13
+ "@codeyam-editor/codeyam-editor-darwin-x64": "0.1.10",
14
+ "@codeyam-editor/codeyam-editor-linux-x64": "0.1.10",
15
+ "@codeyam-editor/codeyam-editor-win32-x64": "0.1.10"
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-BPLKgwon.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{h as E}from"./index-sW8wcg7v.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};