@tonyclaw/agent-inspector 3.0.44 → 3.0.45

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 (80) hide show
  1. package/.output/cli.js +20743 -16945
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-DQHjxFO6.js → CompareDrawer-B3_TLTJh.js} +1 -1
  4. package/.output/public/assets/{InspectorPet-D1A4505B.js → InspectorPet-Cpn6hv4P.js} +1 -1
  5. package/.output/public/assets/{ProxyViewerContainer-BhpIgfBi.js → ProxyViewerContainer-BEAhuGOJ.js} +27 -27
  6. package/.output/public/assets/{ReplayDialog-C5vmbecv.js → ReplayDialog-B3EKVdJk.js} +1 -1
  7. package/.output/public/assets/{RequestAnatomy-CPGNB8lk.js → RequestAnatomy-COOQjyUC.js} +1 -1
  8. package/.output/public/assets/{ResponseView-DUfrajCm.js → ResponseView-DBCjkwye.js} +1 -1
  9. package/.output/public/assets/{StreamingChunkSequence-nbeCQqOz.js → StreamingChunkSequence-CuXhDgMo.js} +1 -1
  10. package/.output/public/assets/{_sessionId-mw3aA8Bp.js → _sessionId-BJlM3nmt.js} +1 -1
  11. package/.output/public/assets/{_sessionId-CDhRgzf6.js → _sessionId-zbgYl7ZJ.js} +1 -1
  12. package/.output/public/assets/{index-B2eoeT-Z.js → index-BIK4bPTv.js} +1 -1
  13. package/.output/public/assets/{index-C6qZwYlR.js → index-BZo_8koU.js} +15 -15
  14. package/.output/public/assets/{index-CX7_rf7o.js → index-D2Qw6Ri2.js} +1 -1
  15. package/.output/public/assets/{index-BWjeqxbk.css → index-ZWschkCh.css} +1 -1
  16. package/.output/public/assets/{index-BfRhTvOd.js → index-xF_NY8Yb.js} +5 -5
  17. package/.output/public/assets/{json-viewer-BLmF1sOZ.js → json-viewer-B-Ao6pwW.js} +1 -1
  18. package/.output/public/assets/{jszip.min-C9rCFoU3.js → jszip.min-B_rfAUCe.js} +1 -1
  19. package/.output/server/_libs/modelcontextprotocol__core.mjs +25 -25
  20. package/.output/server/_libs/modelcontextprotocol__server.mjs +2 -2
  21. package/.output/server/_libs/zod.mjs +6 -6
  22. package/.output/server/{_sessionId-U54BAqdp.mjs → _sessionId-CJ99gZFV.mjs} +3 -1
  23. package/.output/server/{_sessionId-E_Dmopc-.mjs → _sessionId-DEjScBpK.mjs} +5 -3
  24. package/.output/server/_ssr/{CompareDrawer-CksatPed.mjs → CompareDrawer-DtOIMeQB.mjs} +4 -2
  25. package/.output/server/_ssr/{InspectorPet-DNc4GQ7z.mjs → InspectorPet-CXc4oCBQ.mjs} +3 -1
  26. package/.output/server/_ssr/{ProxyViewerContainer-B02Ey0p_.mjs → ProxyViewerContainer-DVPlwfkt.mjs} +52 -27
  27. package/.output/server/_ssr/{ReplayDialog-DdMvHJF1.mjs → ReplayDialog-BQEA95qC.mjs} +6 -4
  28. package/.output/server/_ssr/{RequestAnatomy--vh2Z8__.mjs → RequestAnatomy-BMyd8B7Q.mjs} +4 -2
  29. package/.output/server/_ssr/{ResponseView-Dhxc-cKC.mjs → ResponseView-qrTaEIM8.mjs} +4 -2
  30. package/.output/server/_ssr/{StreamingChunkSequence-BG0EQmaD.mjs → StreamingChunkSequence-BFTL8mIy.mjs} +5 -3
  31. package/.output/server/_ssr/{index-lcfulIXa.mjs → index-Bcj1Hcy4.mjs} +4 -2
  32. package/.output/server/_ssr/{index-D0At9nfd.mjs → index-DW-M7XUG.mjs} +3 -1
  33. package/.output/server/_ssr/index.mjs +4 -3
  34. package/.output/server/_ssr/{json-viewer-My1J1_5R.mjs → json-viewer-DiI0Yjsn.mjs} +4 -2
  35. package/.output/server/_ssr/publicBasePathContext-5264L3rX.mjs +148 -0
  36. package/.output/server/_ssr/{router-DWcUFPR3.mjs → router-BJ_ltLim.mjs} +2432 -475
  37. package/.output/server/_ssr/start-C6MjPjxp.mjs +57 -0
  38. package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +4 -0
  39. package/.output/server/index.mjs +92 -92
  40. package/.output/workers/logFinalizer.worker.js +4 -0
  41. package/.output/workers/sessionWorkerEntry.js +4 -0
  42. package/README.md +221 -25
  43. package/docs/instance-control.openapi.yaml +306 -0
  44. package/package.json +4 -1
  45. package/src/cli/alias.ts +440 -0
  46. package/src/cli/instance.ts +1037 -0
  47. package/src/cli/instanceArgs.ts +266 -0
  48. package/src/cli/instanceControl.ts +183 -0
  49. package/src/cli/instanceModel.ts +275 -0
  50. package/src/cli/instanceRegistry.ts +740 -0
  51. package/src/cli/onboard.ts +123 -35
  52. package/src/cli/onboardTarget.ts +179 -0
  53. package/src/cli/templates/codex-skill-onboard.ts +76 -28
  54. package/src/cli/templates/skill-onboard.ts +93 -59
  55. package/src/cli.ts +154 -16
  56. package/src/components/ProxyViewer.tsx +13 -5
  57. package/src/components/providers/SettingsDialog.tsx +13 -8
  58. package/src/lib/basePath.ts +8 -2
  59. package/src/lib/codingAgentEndpoints.ts +16 -0
  60. package/src/lib/instanceContract.ts +220 -0
  61. package/src/lib/managedInstance.ts +104 -0
  62. package/src/lib/publicBasePathContext.ts +107 -0
  63. package/src/mcp/instanceHandlers.ts +149 -0
  64. package/src/mcp/loopback.ts +16 -5
  65. package/src/mcp/mode.ts +25 -0
  66. package/src/mcp/server.ts +258 -18
  67. package/src/mcp/toolHandlers.ts +2 -2
  68. package/src/proxy/identityProxy.ts +655 -36
  69. package/src/proxy/runtimeShutdown.ts +73 -1
  70. package/src/proxy/sessionInfo.ts +5 -4
  71. package/src/routes/api/-instances.ts +109 -0
  72. package/src/routes/api/instances.$name.connection.ts +12 -0
  73. package/src/routes/api/instances.$name.restart.ts +23 -0
  74. package/src/routes/api/instances.$name.start.ts +18 -0
  75. package/src/routes/api/instances.$name.stop.ts +23 -0
  76. package/src/routes/api/instances.$name.ts +12 -0
  77. package/src/routes/api/instances.ts +16 -0
  78. package/src/start.ts +10 -0
  79. package/.output/server/_ssr/start-HYkvq4Ni.mjs +0 -4
  80. package/.output/server/_tanstack-start-manifest_v-B2chR8ef.mjs +0 -4
@@ -1,4 +1,5 @@
1
1
  import { c as createRouter, a as createRootRoute, b as createFileRoute, l as lazyRouteComponent, O as Outlet, H as HeadContent, S as Scripts } from "../_libs/tanstack__react-router.mjs";
2
+ import { h as getRouterBasePath, r as runWithRequestPublicBasePath, a as getPublicBasePath, w as withBasePath, s as stripBasePath, g as getConfiguredBasePath, n as normalizeBasePath, e as appendBasePathToOrigin, A as AGENT_INSPECTOR_BASE_PATH_META_NAME, f as AGENT_INSPECTOR_BASE_PATH_ENV, b as getPublicPort, c as AGENT_INSPECTOR_PUBLIC_BASE_PATH_HEADER, d as AGENT_INSPECTOR_PUBLIC_PORT_HEADER } from "./publicBasePathContext-5264L3rX.mjs";
2
3
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
3
4
  import { S as SWRConfig } from "../_libs/swr.mjs";
4
5
  import { c as cva } from "../_libs/class-variance-authority.mjs";
@@ -6,8 +7,8 @@ import { c as clsx } from "../_libs/clsx.mjs";
6
7
  import { t as twMerge } from "../_libs/tailwind-merge.mjs";
7
8
  import { randomUUID, timingSafeEqual, createHash, createDecipheriv, randomBytes, createCipheriv } from "node:crypto";
8
9
  import fs, { readdir, open, readFile, unlink, writeFile, appendFile, stat, rename, rm, statfs } from "node:fs/promises";
9
- import path, { basename, join, dirname, isAbsolute, resolve, relative } from "node:path";
10
- import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync, copyFileSync, createReadStream, mkdirSync, statSync, readdirSync, rmSync, chmodSync, cpSync, lstatSync, appendFileSync, createWriteStream } from "node:fs";
10
+ import path, { basename, join, dirname, isAbsolute, resolve, win32, posix, relative } from "node:path";
11
+ import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync, copyFileSync, createReadStream, mkdirSync, statSync, readdirSync, rmSync, chmodSync, cpSync, lstatSync, appendFileSync, createWriteStream, realpathSync, openSync, closeSync } from "node:fs";
11
12
  import { spawn, execFile, spawnSync } from "node:child_process";
12
13
  import { Buffer } from "node:buffer";
13
14
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -17,12 +18,12 @@ import { C as Conf } from "../_libs/conf.mjs";
17
18
  import { randomUUID as randomUUID$1 } from "crypto";
18
19
  import { promisify } from "node:util";
19
20
  import { lookup } from "node:dns/promises";
20
- import { isIP } from "node:net";
21
+ import { isIP, createServer } from "node:net";
21
22
  import assert from "node:assert/strict";
22
23
  import { M as McpServer, W as WebStandardStreamableHTTPServerTransport, R as ResourceTemplate } from "../_libs/modelcontextprotocol__server.mjs";
23
24
  import { J as JSZip } from "../_libs/jszip.mjs";
24
25
  import { homedir } from "node:os";
25
- import { o as object, c as string, e as array, n as number, r as record, f as _enum, u as union, h as unknown, a as literal, d as boolean, k as discriminatedUnion, _ as _null, b as lazy } from "../_libs/zod.mjs";
26
+ import { o as object, c as string, f as array, n as number, r as record, g as _enum, u as union, j as unknown, a as literal, e as boolean, k as discriminatedUnion, _ as _null, b as lazy, q as url, d as datetime } from "../_libs/zod.mjs";
26
27
  import "../_libs/tanstack__router-core.mjs";
27
28
  import "../_libs/cookie-es.mjs";
28
29
  import "../_libs/seroval.mjs";
@@ -35,6 +36,7 @@ import "util";
35
36
  import "async_hooks";
36
37
  import "stream";
37
38
  import "../_libs/isbot.mjs";
39
+ import "node:async_hooks";
38
40
  import "../_libs/use-sync-external-store.mjs";
39
41
  import "../_libs/dequal.mjs";
40
42
  import "node:process";
@@ -70,52 +72,6 @@ import "../_libs/lie.mjs";
70
72
  import "../_libs/immediate.mjs";
71
73
  import "../_libs/setimmediate.mjs";
72
74
  import "../_libs/pako.mjs";
73
- const AGENT_INSPECTOR_BASE_PATH_ENV = "AGENT_INSPECTOR_BASE_PATH";
74
- const AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH_ENV = "AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH";
75
- const AGENT_INSPECTOR_BASE_PATH_META_NAME = "agent-inspector-base-path";
76
- const DEFAULT_AGENT_INSPECTOR_BASE_PATH = "/inspector";
77
- function trimSlashes(value) {
78
- return value.replace(/^\/+/u, "").replace(/\/+$/u, "");
79
- }
80
- function normalizeBasePath(value) {
81
- const trimmed = value?.trim();
82
- if (trimmed === void 0 || trimmed.length === 0 || trimmed === "/") return "";
83
- const path2 = trimSlashes(trimmed);
84
- if (path2.length === 0) return "";
85
- return `/${path2}`;
86
- }
87
- function readDocumentBasePath() {
88
- if (typeof document === "undefined") return void 0;
89
- return document.querySelector(`meta[name="${AGENT_INSPECTOR_BASE_PATH_META_NAME}"]`)?.getAttribute("content") ?? void 0;
90
- }
91
- function readProcessBasePath() {
92
- if (typeof process === "undefined") return void 0;
93
- return process.env[AGENT_INSPECTOR_BASE_PATH_ENV];
94
- }
95
- function getConfiguredBasePath(env) {
96
- return normalizeBasePath(
97
- env?.[AGENT_INSPECTOR_BASE_PATH_ENV] ?? readProcessBasePath() ?? readDocumentBasePath() ?? "/" ?? DEFAULT_AGENT_INSPECTOR_BASE_PATH
98
- );
99
- }
100
- function getRouterBasePath(env) {
101
- if (env?.[AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH_ENV] === "1") return "";
102
- return getConfiguredBasePath(env);
103
- }
104
- function withBasePath(path2, basePath = getConfiguredBasePath()) {
105
- const normalized = normalizeBasePath(basePath);
106
- if (/^[a-z][a-z0-9+.-]*:/iu.test(path2)) return path2;
107
- if (normalized.length === 0) return path2;
108
- if (path2.length === 0 || path2 === "/") return normalized;
109
- if (path2.startsWith(`${normalized}/`) || path2 === normalized) return path2;
110
- return path2.startsWith("/") ? `${normalized}${path2}` : `${normalized}/${path2}`;
111
- }
112
- function stripBasePath(pathname, basePath = getConfiguredBasePath()) {
113
- const normalized = normalizeBasePath(basePath);
114
- if (normalized.length === 0) return pathname;
115
- if (pathname === normalized) return "/";
116
- if (pathname.startsWith(`${normalized}/`)) return pathname.slice(normalized.length);
117
- return pathname;
118
- }
119
75
  const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20role='img'%20aria-label='Agent%20Inspector'%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M5%2013%20C5%209%208%207%2012%207%20C16%207%2019%209%2019%2013%20C19%2016%2016%2018%2012%2018%20C8%2018%205%2016%205%2013%20Z'%20/%3e%3cpath%20d='M5%2011%20C3.5%209.5%201.5%2010%202%2012.5%20C2.5%2014%204%2013.5%205%2012.5'%20/%3e%3cpath%20d='M19%2011%20C20.5%209.5%2022.5%2010%2022%2012.5%20C21.5%2014%2020%2013.5%2019%2012.5'%20/%3e%3cline%20x1='10'%20y1='7'%20x2='9.5'%20y2='5'%20/%3e%3cline%20x1='14'%20y1='7'%20x2='14.5'%20y2='5'%20/%3e%3cline%20x1='6.5'%20y1='16'%20x2='4.5'%20y2='19.5'%20/%3e%3cline%20x1='9'%20y1='17.5'%20x2='8'%20y2='20.5'%20/%3e%3cline%20x1='15'%20y1='17.5'%20x2='16'%20y2='20.5'%20/%3e%3cline%20x1='17.5'%20y1='16'%20x2='19.5'%20y2='19.5'%20/%3e%3c/g%3e%3ccircle%20cx='9.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='14.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3c/svg%3e";
120
76
  function restoreSelection(selection, ranges) {
121
77
  if (selection === null) return;
@@ -339,8 +295,8 @@ function SafeErrorFallback({
339
295
  }) {
340
296
  const [copied, setCopied] = reactExports.useState(false);
341
297
  const handleCopy = reactExports.useCallback(() => {
342
- void copyTextToClipboard(reference).then((success) => {
343
- if (!success) return;
298
+ void copyTextToClipboard(reference).then((success2) => {
299
+ if (!success2) return;
344
300
  setCopied(true);
345
301
  });
346
302
  }, [reference]);
@@ -447,7 +403,7 @@ function SafeRouteError({
447
403
  }
448
404
  );
449
405
  }
450
- const appCss = "/assets/index-BWjeqxbk.css";
406
+ const appCss = "/assets/index-ZWschkCh.css";
451
407
  const CHUNK_LOAD_RELOAD_AT_KEY = "agent-inspector.chunkLoadReloadAt";
452
408
  const CHUNK_LOAD_RELOAD_WINDOW_MS = 15e3;
453
409
  const CHUNK_LOAD_FAILURE_PATTERNS = [
@@ -700,7 +656,7 @@ const uiScaleBootstrapScript = `
700
656
  }
701
657
  })();
702
658
  `;
703
- const Route$O = createRootRoute({
659
+ const Route$U = createRootRoute({
704
660
  head: () => ({
705
661
  meta: [
706
662
  { charSet: "utf-8" },
@@ -3002,11 +2958,11 @@ function destroyAllSessionProcesses() {
3002
2958
  sp.destroy();
3003
2959
  }
3004
2960
  }
3005
- function isRecord(value) {
2961
+ function isRecord$2(value) {
3006
2962
  return typeof value === "object" && value !== null && !Array.isArray(value);
3007
2963
  }
3008
2964
  function readProperty$3(value, name2) {
3009
- if (!isRecord(value)) return void 0;
2965
+ if (!isRecord$2(value)) return void 0;
3010
2966
  const descriptor = Object.getOwnPropertyDescriptor(value, name2);
3011
2967
  return descriptor === void 0 ? void 0 : descriptor.value;
3012
2968
  }
@@ -4015,13 +3971,13 @@ function buildAbsoluteUrl(baseUrl, path2) {
4015
3971
  }
4016
3972
  function buildApiPath(sessionId) {
4017
3973
  return buildRelativePath(
4018
- withBasePath("/api/sessions", getConfiguredBasePath(process.env)),
3974
+ withBasePath("/api/sessions", getPublicBasePath()),
4019
3975
  new URLSearchParams({ sessionId })
4020
3976
  );
4021
3977
  }
4022
3978
  function buildCompactLogsPath(sessionId) {
4023
3979
  return buildRelativePath(
4024
- withBasePath("/api/logs", getConfiguredBasePath(process.env)),
3980
+ withBasePath("/api/logs", getPublicBasePath()),
4025
3981
  new URLSearchParams({ compact: "1", sessionId })
4026
3982
  );
4027
3983
  }
@@ -4100,7 +4056,7 @@ function buildSessionInfo(input) {
4100
4056
  const queuedTasks = input.snapshot?.queuedTasks ?? 0;
4101
4057
  const runningTasks = input.snapshot?.runningTasks ?? 0;
4102
4058
  const lastTaskError = normalizeString(input.snapshot?.lastTaskError);
4103
- const inspectorPath = getSessionPath(input.sessionId, getConfiguredBasePath(process.env));
4059
+ const inspectorPath = getSessionPath(input.sessionId, getPublicBasePath());
4104
4060
  const apiPath = buildApiPath(input.sessionId);
4105
4061
  const compactLogsPath = buildCompactLogsPath(input.sessionId);
4106
4062
  const latestLogs = summaries.slice(0, latestLogLimit).map((summary, index) => ({
@@ -5838,7 +5794,7 @@ function readStringArray(value, key) {
5838
5794
  }
5839
5795
  function readObject(value, key) {
5840
5796
  const property = readProperty$3(value, key);
5841
- return isRecord(property) ? property : null;
5797
+ return isRecord$2(property) ? property : null;
5842
5798
  }
5843
5799
  function normalizeExpectedType(typeName) {
5844
5800
  switch (typeName) {
@@ -5883,7 +5839,7 @@ function actualType(value) {
5883
5839
  case "function":
5884
5840
  case "object":
5885
5841
  case "symbol":
5886
- return isRecord(value) ? "object" : "unknown";
5842
+ return isRecord$2(value) ? "object" : "unknown";
5887
5843
  }
5888
5844
  return "unknown";
5889
5845
  }
@@ -5900,7 +5856,7 @@ function matchesExpectedType(value, expected) {
5900
5856
  case "number":
5901
5857
  return typeof value === "number" && Number.isFinite(value);
5902
5858
  case "object":
5903
- return isRecord(value);
5859
+ return isRecord$2(value);
5904
5860
  case "string":
5905
5861
  return typeof value === "string";
5906
5862
  }
@@ -6005,7 +5961,7 @@ function validateEnum(schema, value, toolName, path2, warnings) {
6005
5961
  }
6006
5962
  }
6007
5963
  function validateValueAgainstSchema(schema, value, toolName, path2, warnings) {
6008
- if (!isRecord(schema)) return;
5964
+ if (!isRecord$2(schema)) return;
6009
5965
  const expectedTypes = schemaTypes(schema);
6010
5966
  if (expectedTypes.length > 0 && !matchesAnyExpectedType(value, expectedTypes)) {
6011
5967
  addTypeWarning(warnings, toolName, path2, expectedTypes, value);
@@ -6013,7 +5969,7 @@ function validateValueAgainstSchema(schema, value, toolName, path2, warnings) {
6013
5969
  }
6014
5970
  validateEnum(schema, value, toolName, path2, warnings);
6015
5971
  if (schemaAllowsObjectValidation(schema, expectedTypes)) {
6016
- if (isRecord(value)) {
5972
+ if (isRecord$2(value)) {
6017
5973
  validateObjectSchema(schema, value, toolName, path2, warnings);
6018
5974
  } else if (expectedTypes.length === 0) {
6019
5975
  warnings.push(
@@ -6034,7 +5990,7 @@ function validateValueAgainstSchema(schema, value, toolName, path2, warnings) {
6034
5990
  function extractAnthropicToolSchemas(request) {
6035
5991
  const tools = /* @__PURE__ */ new Map();
6036
5992
  for (const tool of readArray(request, "tools")) {
6037
- if (!isRecord(tool)) continue;
5993
+ if (!isRecord$2(tool)) continue;
6038
5994
  const name2 = readString(tool, "name");
6039
5995
  if (name2 === null || name2 === "") continue;
6040
5996
  tools.set(name2, {
@@ -6848,7 +6804,7 @@ async function readinessResponse() {
6848
6804
  headers: { "cache-control": "no-store" }
6849
6805
  });
6850
6806
  }
6851
- const Route$N = createFileRoute("/readyz")({
6807
+ const Route$T = createFileRoute("/readyz")({
6852
6808
  server: {
6853
6809
  handlers: {
6854
6810
  GET: readinessResponse
@@ -6858,23 +6814,23 @@ const Route$N = createFileRoute("/readyz")({
6858
6814
  function livenessResponse() {
6859
6815
  return Response.json({ status: "ok" }, { headers: { "cache-control": "no-store" } });
6860
6816
  }
6861
- const Route$M = createFileRoute("/livez")({
6817
+ const Route$S = createFileRoute("/livez")({
6862
6818
  server: {
6863
6819
  handlers: {
6864
6820
  GET: livenessResponse
6865
6821
  }
6866
6822
  }
6867
6823
  });
6868
- const $$splitErrorComponentImporter$1 = () => import("./index-D0At9nfd.mjs");
6869
- const $$splitComponentImporter$1 = () => import("./index-lcfulIXa.mjs");
6870
- const Route$L = createFileRoute("/")({
6824
+ const $$splitErrorComponentImporter$1 = () => import("./index-DW-M7XUG.mjs");
6825
+ const $$splitComponentImporter$1 = () => import("./index-Bcj1Hcy4.mjs");
6826
+ const Route$R = createFileRoute("/")({
6871
6827
  ssr: false,
6872
6828
  component: lazyRouteComponent($$splitComponentImporter$1, "component"),
6873
6829
  errorComponent: lazyRouteComponent($$splitErrorComponentImporter$1, "errorComponent")
6874
6830
  });
6875
- const $$splitErrorComponentImporter = () => import("../_sessionId-U54BAqdp.mjs");
6876
- const $$splitComponentImporter = () => import("../_sessionId-E_Dmopc-.mjs");
6877
- const Route$K = createFileRoute("/session/$sessionId")({
6831
+ const $$splitErrorComponentImporter = () => import("../_sessionId-CJ99gZFV.mjs");
6832
+ const $$splitComponentImporter = () => import("../_sessionId-DEjScBpK.mjs");
6833
+ const Route$Q = createFileRoute("/session/$sessionId")({
6878
6834
  ssr: false,
6879
6835
  component: lazyRouteComponent($$splitComponentImporter, "component"),
6880
6836
  errorComponent: lazyRouteComponent($$splitErrorComponentImporter, "errorComponent"),
@@ -7302,9 +7258,9 @@ function providerEntryMatches(provider, entry) {
7302
7258
  return providerName.includes(normalized) || normalized.includes(providerName);
7303
7259
  });
7304
7260
  if (nameMatches) return true;
7305
- const normalizedProviderUrls = providerBaseUrls(provider).map((url) => normalizeUrl(url)).filter((url) => url !== null);
7306
- const baseUrlMatches = entry.baseUrls.some((url) => {
7307
- const normalized = normalizeUrl(url);
7261
+ const normalizedProviderUrls = providerBaseUrls(provider).map((url2) => normalizeUrl(url2)).filter((url2) => url2 !== null);
7262
+ const baseUrlMatches = entry.baseUrls.some((url2) => {
7263
+ const normalized = normalizeUrl(url2);
7308
7264
  return normalized !== null && normalizedProviderUrls.includes(normalized);
7309
7265
  });
7310
7266
  if (baseUrlMatches) return true;
@@ -8260,8 +8216,8 @@ function isZhipuProvider(provider) {
8260
8216
  return normalizedName.includes(normalizedAlias) || normalizedAlias.includes(normalizedName);
8261
8217
  });
8262
8218
  if (nameMatches) return true;
8263
- return providerRoutingUrls(provider).some((url) => {
8264
- const normalizedUrl = url.toLowerCase().replace(/\/+$/, "");
8219
+ return providerRoutingUrls(provider).some((url2) => {
8220
+ const normalizedUrl = url2.toLowerCase().replace(/\/+$/, "");
8265
8221
  return ZHIPU_BASE_URL_MARKERS.some((marker) => normalizedUrl.includes(marker));
8266
8222
  });
8267
8223
  }
@@ -9405,9 +9361,9 @@ function describeApiRoute(apiPath) {
9405
9361
  const normalizedPath = isOpenAI && !apiPath.startsWith("/v1/") ? `/v1${apiPath}` : apiPath;
9406
9362
  return { apiPath, endpointPath, isChatCompletions, isResponses, isOpenAI, normalizedPath };
9407
9363
  }
9408
- function getProxyApiPath(url) {
9409
- const pathname = stripBasePath(url.pathname, getConfiguredBasePath(process.env));
9410
- return pathname.replace(/^\/proxy/, "") + url.search;
9364
+ function getProxyApiPath(url2) {
9365
+ const pathname = stripBasePath(url2.pathname, getConfiguredBasePath(process.env));
9366
+ return pathname.replace(/^\/proxy/, "") + url2.search;
9411
9367
  }
9412
9368
  function selectUpstreamBase(route, provider) {
9413
9369
  if (provider === null) {
@@ -9472,8 +9428,8 @@ function buildProxyHeaders(originalHeaders, captureRawHeaders) {
9472
9428
  }
9473
9429
  return { headers, rawHeaders };
9474
9430
  }
9475
- function parseRequestPath(req, url) {
9476
- const route = describeApiRoute(getProxyApiPath(url));
9431
+ function parseRequestPath(req, url2) {
9432
+ const route = describeApiRoute(getProxyApiPath(url2));
9477
9433
  const isPost = req.method === "POST";
9478
9434
  const isChatCompletions = isPost && route.isChatCompletions;
9479
9435
  const isMessages = isPost && (route.endpointPath === PATH_V1_MESSAGES$1 || route.isChatCompletions);
@@ -9641,8 +9597,8 @@ function handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log,
9641
9597
  });
9642
9598
  }
9643
9599
  async function handleAdmittedProxy(req) {
9644
- const url = new URL(req.url);
9645
- const parsed = parseRequestPath(req, url);
9600
+ const url2 = new URL(req.url);
9601
+ const parsed = parseRequestPath(req, url2);
9646
9602
  const bodyRead = await readBodyWithLimit(req, MAX_REQUEST_BODY_BYTES);
9647
9603
  if (!bodyRead.ok) {
9648
9604
  logger.warn(`[handler] Rejected oversized request body: ${req.method} ${parsed.apiPath}`);
@@ -9818,7 +9774,7 @@ async function handleProxy(req) {
9818
9774
  return await Promise.reject(error);
9819
9775
  }
9820
9776
  }
9821
- const Route$J = createFileRoute("/proxy/$")({
9777
+ const Route$P = createFileRoute("/proxy/$")({
9822
9778
  server: {
9823
9779
  handlers: {
9824
9780
  GET: ({ request }) => handleProxy(request),
@@ -9833,18 +9789,18 @@ const Route$J = createFileRoute("/proxy/$")({
9833
9789
  function parseBooleanFlag(value) {
9834
9790
  return value === "1" || value === "true";
9835
9791
  }
9836
- const Route$I = createFileRoute("/api/sessions")({
9792
+ const Route$O = createFileRoute("/api/sessions")({
9837
9793
  server: {
9838
9794
  handlers: {
9839
9795
  GET: async ({ request }) => {
9840
- const url = new URL(request.url);
9841
- const sessionId = url.searchParams.get("sessionId");
9796
+ const url2 = new URL(request.url);
9797
+ const sessionId = url2.searchParams.get("sessionId");
9842
9798
  if (sessionId !== null) {
9843
9799
  if (sessionId.length === 0) {
9844
9800
  return Response.json({ error: "sessionId is required" }, { status: 400 });
9845
9801
  }
9846
9802
  const limitResult = parseBoundedIntegerParameter({
9847
- value: url.searchParams.get("limit"),
9803
+ value: url2.searchParams.get("limit"),
9848
9804
  parameter: "limit",
9849
9805
  fallback: SESSION_INFO_DEFAULT_LATEST_LOG_LIMIT,
9850
9806
  minimum: 1,
@@ -9853,8 +9809,8 @@ const Route$I = createFileRoute("/api/sessions")({
9853
9809
  });
9854
9810
  if (!limitResult.ok) return limitResult.response;
9855
9811
  const info = await getSessionInfo(sessionId, {
9856
- baseUrl: url.origin,
9857
- includeHistory: parseBooleanFlag(url.searchParams.get("includeHistory")),
9812
+ baseUrl: url2.origin,
9813
+ includeHistory: parseBooleanFlag(url2.searchParams.get("includeHistory")),
9858
9814
  latestLogLimit: limitResult.value
9859
9815
  });
9860
9816
  if (info === null) {
@@ -9862,7 +9818,7 @@ const Route$I = createFileRoute("/api/sessions")({
9862
9818
  }
9863
9819
  return Response.json(info);
9864
9820
  }
9865
- const details = url.searchParams.get("details");
9821
+ const details = url2.searchParams.get("details");
9866
9822
  if (details === "true" || details === "1") {
9867
9823
  return Response.json(getSessionSnapshots());
9868
9824
  }
@@ -11226,7 +11182,7 @@ function failureFromRun(run) {
11226
11182
  };
11227
11183
  }
11228
11184
  function listRecentFailures(limit) {
11229
- const failures = listRuns().map(failureFromRun).filter((failure) => failure !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
11185
+ const failures = listRuns().map(failureFromRun).filter((failure2) => failure2 !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
11230
11186
  const clampedLimit = clampRecentFailuresLimit(limit);
11231
11187
  return {
11232
11188
  failures: failures.slice(0, clampedLimit),
@@ -11282,14 +11238,14 @@ async function readJsonBody$6(request) {
11282
11238
  return { ok: false };
11283
11239
  }
11284
11240
  }
11285
- const Route$H = createFileRoute("/api/runs")({
11241
+ const Route$N = createFileRoute("/api/runs")({
11286
11242
  server: {
11287
11243
  handlers: {
11288
11244
  GET: ({ request }) => {
11289
- const url = new URL(request.url);
11290
- if (url.searchParams.get("failures") === "1") {
11245
+ const url2 = new URL(request.url);
11246
+ if (url2.searchParams.get("failures") === "1") {
11291
11247
  const limitResult = parseBoundedIntegerParameter({
11292
- value: url.searchParams.get("limit"),
11248
+ value: url2.searchParams.get("limit"),
11293
11249
  parameter: "limit",
11294
11250
  fallback: RECENT_FAILURES_DEFAULT_LIMIT,
11295
11251
  minimum: 1,
@@ -11334,7 +11290,7 @@ const ProviderInputSchema = object({
11334
11290
  modelMetadata: ProviderModelMetadataListSchema.optional(),
11335
11291
  source: _enum(["company", "personal"]).optional()
11336
11292
  });
11337
- const Route$G = createFileRoute("/api/providers")({
11293
+ const Route$M = createFileRoute("/api/providers")({
11338
11294
  server: {
11339
11295
  handlers: {
11340
11296
  GET: () => {
@@ -11874,8 +11830,8 @@ function warningObservation(log, warning) {
11874
11830
  }
11875
11831
  function addLogObservations(map, logs, slowResponseThresholdSeconds) {
11876
11832
  for (const log of logs) {
11877
- const failure = requestFailureObservation(log);
11878
- if (failure !== null) addObservation(map, failure);
11833
+ const failure2 = requestFailureObservation(log);
11834
+ if (failure2 !== null) addObservation(map, failure2);
11879
11835
  const slow = slowResponseObservation(log, slowResponseThresholdSeconds);
11880
11836
  if (slow !== null) addObservation(map, slow);
11881
11837
  for (const warning of log.warnings ?? []) {
@@ -11883,8 +11839,8 @@ function addLogObservations(map, logs, slowResponseThresholdSeconds) {
11883
11839
  }
11884
11840
  }
11885
11841
  }
11886
- function alertSeverityFromFailure(failure) {
11887
- switch (failure.classification.severity) {
11842
+ function alertSeverityFromFailure(failure2) {
11843
+ switch (failure2.classification.severity) {
11888
11844
  case "high":
11889
11845
  return "critical";
11890
11846
  case "medium":
@@ -11894,47 +11850,47 @@ function alertSeverityFromFailure(failure) {
11894
11850
  return "notice";
11895
11851
  }
11896
11852
  }
11897
- function providerFromRun(failure) {
11898
- const provider = failure.run.metadata["provider"] ?? failure.run.metadata["providerName"];
11853
+ function providerFromRun(failure2) {
11854
+ const provider = failure2.run.metadata["provider"] ?? failure2.run.metadata["providerName"];
11899
11855
  return typeof provider === "string" && provider.length > 0 ? provider : null;
11900
11856
  }
11901
- function modelFromRun(failure) {
11902
- const model = failure.run.metadata["model"] ?? failure.run.metadata["modelName"];
11857
+ function modelFromRun(failure2) {
11858
+ const model = failure2.run.metadata["model"] ?? failure2.run.metadata["modelName"];
11903
11859
  return typeof model === "string" && model.length > 0 ? model : null;
11904
11860
  }
11905
- function runFailureObservation(failure) {
11906
- const groupId = failure.run.groupId;
11907
- const logEvidenceLinks = failure.classification.evidenceLogIds.map(logEvidence$1);
11861
+ function runFailureObservation(failure2) {
11862
+ const groupId = failure2.run.groupId;
11863
+ const logEvidenceLinks = failure2.classification.evidenceLogIds.map(logEvidence$1);
11908
11864
  const links = mergeEvidence(
11909
- baseEvidence(null, failure.sessionId, failure.run.id, groupId),
11865
+ baseEvidence(null, failure2.sessionId, failure2.run.id, groupId),
11910
11866
  logEvidenceLinks
11911
11867
  );
11912
11868
  return {
11913
- fingerprint: fingerprint(["run", failure.run.id, failure.classification.category]),
11914
- severity: alertSeverityFromFailure(failure),
11869
+ fingerprint: fingerprint(["run", failure2.run.id, failure2.classification.category]),
11870
+ severity: alertSeverityFromFailure(failure2),
11915
11871
  category: "run-failure",
11916
11872
  source: "run",
11917
- title: `Run ${failure.run.status}`,
11918
- message: failure.classification.summary,
11919
- observedAt: failure.updatedAt,
11920
- logId: failure.classification.evidenceLogIds[0] ?? null,
11921
- sessionId: failure.sessionId,
11922
- runId: failure.run.id,
11873
+ title: `Run ${failure2.run.status}`,
11874
+ message: failure2.classification.summary,
11875
+ observedAt: failure2.updatedAt,
11876
+ logId: failure2.classification.evidenceLogIds[0] ?? null,
11877
+ sessionId: failure2.sessionId,
11878
+ runId: failure2.run.id,
11923
11879
  groupId,
11924
- provider: providerFromRun(failure),
11925
- model: modelFromRun(failure),
11880
+ provider: providerFromRun(failure2),
11881
+ model: modelFromRun(failure2),
11926
11882
  apiFormat: null,
11927
11883
  evidence: links,
11928
11884
  metadata: {
11929
- runStatus: failure.run.status,
11930
- failureCategory: failure.classification.category,
11931
- evidenceMarkdownPath: failure.evidenceMarkdownPath
11885
+ runStatus: failure2.run.status,
11886
+ failureCategory: failure2.classification.category,
11887
+ evidenceMarkdownPath: failure2.evidenceMarkdownPath
11932
11888
  }
11933
11889
  };
11934
11890
  }
11935
11891
  function addRunFailureObservations(map, recentFailures) {
11936
- for (const failure of recentFailures) {
11937
- addObservation(map, runFailureObservation(failure));
11892
+ for (const failure2 of recentFailures) {
11893
+ addObservation(map, runFailureObservation(failure2));
11938
11894
  }
11939
11895
  }
11940
11896
  function memberProvider(member) {
@@ -12950,14 +12906,14 @@ const MAX_CONTEXT_CHARS = 18e3;
12950
12906
  const MAX_HISTORY_CHARS = 4e3;
12951
12907
  const PI_AGENT_MAX_OUTPUT_TOKENS = 900;
12952
12908
  const DEFAULT_CONTEXT_WINDOW = 128e3;
12953
- function nonEmpty(value) {
12909
+ function nonEmpty$1(value) {
12954
12910
  return value !== void 0 && value.trim() !== "" ? value.trim() : void 0;
12955
12911
  }
12956
12912
  function firstModel(provider) {
12957
- const explicitModel = nonEmpty(provider.model);
12913
+ const explicitModel = nonEmpty$1(provider.model);
12958
12914
  if (explicitModel !== void 0) return explicitModel;
12959
12915
  for (const model of provider.models) {
12960
- const trimmed = nonEmpty(model);
12916
+ const trimmed = nonEmpty$1(model);
12961
12917
  if (trimmed !== void 0) return trimmed;
12962
12918
  }
12963
12919
  return void 0;
@@ -12978,7 +12934,7 @@ function selectProvider(request) {
12978
12934
  for (const provider of providerCandidates(request)) {
12979
12935
  const modelName = request.model ?? firstModel(provider);
12980
12936
  if (modelName === void 0) continue;
12981
- const responsesBaseUrl = nonEmpty(provider.openaiResponsesBaseUrl);
12937
+ const responsesBaseUrl = nonEmpty$1(provider.openaiResponsesBaseUrl);
12982
12938
  if (responsesBaseUrl !== void 0) {
12983
12939
  return {
12984
12940
  provider,
@@ -12989,7 +12945,7 @@ function selectProvider(request) {
12989
12945
  upstreamPath: "/v1/responses"
12990
12946
  };
12991
12947
  }
12992
- const openaiBaseUrl = nonEmpty(provider.openaiBaseUrl);
12948
+ const openaiBaseUrl = nonEmpty$1(provider.openaiBaseUrl);
12993
12949
  if (openaiBaseUrl !== void 0) {
12994
12950
  return {
12995
12951
  provider,
@@ -13000,7 +12956,7 @@ function selectProvider(request) {
13000
12956
  upstreamPath: "/v1/chat/completions"
13001
12957
  };
13002
12958
  }
13003
- const anthropicBaseUrl = nonEmpty(provider.anthropicBaseUrl);
12959
+ const anthropicBaseUrl = nonEmpty$1(provider.anthropicBaseUrl);
13004
12960
  if (anthropicBaseUrl !== void 0) {
13005
12961
  return {
13006
12962
  provider,
@@ -13131,14 +13087,14 @@ function stripUrlSuffix(value, suffix) {
13131
13087
  }
13132
13088
  function sdkBaseUrlFromFinalUrl(finalUrl, protocol) {
13133
13089
  try {
13134
- const url = new URL(finalUrl);
13135
- const pathname = url.pathname.replace(/\/+$/, "");
13090
+ const url2 = new URL(finalUrl);
13091
+ const pathname = url2.pathname.replace(/\/+$/, "");
13136
13092
  const suffixes = protocol === "openaiResponses" ? ["/responses"] : protocol === "openaiChat" ? ["/chat/completions"] : ["/v1/messages", "/messages"];
13137
13093
  for (const suffix of suffixes) {
13138
13094
  const nextPath = stripUrlSuffix(pathname, suffix);
13139
13095
  if (nextPath !== null) {
13140
- url.pathname = nextPath;
13141
- return url.toString().replace(/\/+$/, "");
13096
+ url2.pathname = nextPath;
13097
+ return url2.toString().replace(/\/+$/, "");
13142
13098
  }
13143
13099
  }
13144
13100
  } catch {
@@ -13278,7 +13234,7 @@ async function runPiAgent(request) {
13278
13234
  queryStats: retrieval.queryStats
13279
13235
  };
13280
13236
  }
13281
- const Route$F = createFileRoute("/api/pi-agent")({
13237
+ const Route$L = createFileRoute("/api/pi-agent")({
13282
13238
  server: {
13283
13239
  handlers: {
13284
13240
  POST: async ({ request }) => {
@@ -13301,7 +13257,7 @@ const Route$F = createFileRoute("/api/pi-agent")({
13301
13257
  }
13302
13258
  }
13303
13259
  });
13304
- const Route$E = createFileRoute("/api/models")({
13260
+ const Route$K = createFileRoute("/api/models")({
13305
13261
  server: {
13306
13262
  handlers: {
13307
13263
  GET: () => Response.json(getModels())
@@ -13309,33 +13265,158 @@ const Route$E = createFileRoute("/api/models")({
13309
13265
  }
13310
13266
  });
13311
13267
  const name = "@tonyclaw/agent-inspector";
13312
- const version = "3.0.44";
13268
+ const version = "3.0.45";
13313
13269
  const packageJson = {
13314
13270
  name,
13315
13271
  version
13316
13272
  };
13317
- let overridePort = null;
13318
- function setCurrentPort(port) {
13319
- if (!Number.isInteger(port) || port <= 0 || port > 65535) {
13320
- throw new Error(`setCurrentPort: invalid port ${port}`);
13321
- }
13322
- overridePort = port;
13323
- }
13324
- function getCurrentPort() {
13325
- if (overridePort !== null) return overridePort;
13326
- const publicPort = process.env["AGENT_INSPECTOR_PUBLIC_PORT"];
13327
- if (publicPort !== void 0 && publicPort !== "") {
13328
- const n = Number(publicPort);
13329
- if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
13330
- }
13331
- const envPort = process.env["PORT"];
13332
- if (envPort !== void 0 && envPort !== "") {
13333
- const n = Number(envPort);
13334
- if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
13335
- }
13336
- throw new Error(
13337
- "Inspector server port not initialized: PORT env var is unset and setCurrentPort() has not been called"
13338
- );
13273
+ const INSTANCE_API_SCHEMA_VERSION = 1;
13274
+ const InstanceStateSchema = _enum(["running", "stopped", "conflict"]);
13275
+ const InstanceStateReasonSchema = _enum(["identity_mismatch", "port_conflict"]);
13276
+ const InstanceUrlsSchema = object({
13277
+ ui: url(),
13278
+ api: url(),
13279
+ health: url(),
13280
+ proxy: url(),
13281
+ openai: url(),
13282
+ mcp: url()
13283
+ }).strict();
13284
+ const InstanceStatusOutputSchema = object({
13285
+ schemaVersion: literal(INSTANCE_API_SCHEMA_VERSION),
13286
+ name: string().min(1),
13287
+ instanceId: string().min(1),
13288
+ state: InstanceStateSchema,
13289
+ stateReason: InstanceStateReasonSchema.nullable(),
13290
+ checkedAt: datetime(),
13291
+ createdAt: datetime(),
13292
+ updatedAt: datetime(),
13293
+ launch: object({
13294
+ launchId: string().min(1),
13295
+ startedAt: datetime()
13296
+ }).strict(),
13297
+ host: string().min(1),
13298
+ publicPort: number().int().min(1).max(65535),
13299
+ upstreamPort: number().int().min(1).max(65535),
13300
+ basePath: string().startsWith("/"),
13301
+ captureMode: _enum(["simple", "full"]),
13302
+ dataDir: string().min(1),
13303
+ supervisorPid: number().int().positive().nullable(),
13304
+ urls: InstanceUrlsSchema
13305
+ }).strict();
13306
+ const InstanceConnectionOutputSchema = object({
13307
+ schemaVersion: literal(INSTANCE_API_SCHEMA_VERSION),
13308
+ instance: InstanceStatusOutputSchema,
13309
+ baseUrl: url(),
13310
+ endpoints: InstanceUrlsSchema,
13311
+ environment: object({
13312
+ ANTHROPIC_BASE_URL: url(),
13313
+ LLM_BASE_URL: url(),
13314
+ OPENAI_BASE_URL: url(),
13315
+ AGENT_INSPECTOR_MCP_URL: url()
13316
+ }).strict(),
13317
+ mcp: object({
13318
+ serverName: string().min(1),
13319
+ transport: literal("streamable-http"),
13320
+ url: url()
13321
+ }).strict(),
13322
+ codex: object({
13323
+ providerName: string().min(1),
13324
+ baseUrl: url(),
13325
+ wireApi: literal("responses")
13326
+ }).strict()
13327
+ }).strict();
13328
+ const InstanceStartRequestSchema = object({
13329
+ port: number().int().min(1).max(65535).optional(),
13330
+ basePath: string().min(1).max(2048).refine(
13331
+ (value) => value.startsWith("/") && !value.includes("?") && !value.includes("#") && !value.includes("\\"),
13332
+ "Base Path must be an absolute URL path without query, hash, or backslash"
13333
+ ).optional(),
13334
+ host: string().min(1).max(253).refine(
13335
+ (value) => value.trim() === value && !value.includes("://") && !value.includes("/") && !value.includes("\\") && !/\s/u.test(value),
13336
+ "Host must be a hostname or IP address without protocol, path, or whitespace"
13337
+ ).optional(),
13338
+ captureMode: _enum(["simple", "full"]).optional(),
13339
+ dataDir: string().trim().min(1).max(32767).optional()
13340
+ }).strict();
13341
+ const InstanceEmptyRequestSchema = object({}).strict();
13342
+ const InstanceOperationSchema = _enum(["start", "stop", "restart"]);
13343
+ const InstanceOperationOutcomeSchema = _enum([
13344
+ "created",
13345
+ "started",
13346
+ "already_running",
13347
+ "stopped",
13348
+ "already_stopped",
13349
+ "restarted"
13350
+ ]);
13351
+ const InstanceOperationOutputSchema = object({
13352
+ schemaVersion: literal(INSTANCE_API_SCHEMA_VERSION),
13353
+ operation: InstanceOperationSchema,
13354
+ outcome: InstanceOperationOutcomeSchema,
13355
+ instance: InstanceStatusOutputSchema
13356
+ }).strict();
13357
+ const InstanceListOutputSchema = object({
13358
+ schemaVersion: literal(INSTANCE_API_SCHEMA_VERSION),
13359
+ instances: array(InstanceStatusOutputSchema)
13360
+ }).strict();
13361
+ const InstancePublicErrorCodeSchema = _enum([
13362
+ "argument_invalid",
13363
+ "config_mismatch",
13364
+ "data_dir_conflict",
13365
+ "data_dir_invalid",
13366
+ "identity_mismatch",
13367
+ "instance_not_found",
13368
+ "launch_failed",
13369
+ "launch_unavailable",
13370
+ "lock_not_owned",
13371
+ "lock_timeout",
13372
+ "name_invalid",
13373
+ "port_conflict",
13374
+ "port_exhausted",
13375
+ "port_invalid",
13376
+ "record_invalid",
13377
+ "registry_io",
13378
+ "restart_failed_degraded",
13379
+ "restart_failed_rolled_back",
13380
+ "self_lifecycle_unsupported",
13381
+ "shutdown_failed"
13382
+ ]);
13383
+ const InstancePublicErrorSchema = object({
13384
+ code: InstancePublicErrorCodeSchema,
13385
+ message: string().min(1),
13386
+ retryable: boolean()
13387
+ }).strict();
13388
+ const InstanceErrorOutputSchema = object({
13389
+ schemaVersion: literal(INSTANCE_API_SCHEMA_VERSION),
13390
+ error: InstancePublicErrorSchema
13391
+ }).strict();
13392
+ function isRetryableInstanceError(code) {
13393
+ switch (code) {
13394
+ case "launch_failed":
13395
+ case "launch_unavailable":
13396
+ case "lock_timeout":
13397
+ case "port_exhausted":
13398
+ case "registry_io":
13399
+ case "restart_failed_degraded":
13400
+ case "restart_failed_rolled_back":
13401
+ case "shutdown_failed":
13402
+ return true;
13403
+ case "argument_invalid":
13404
+ case "config_mismatch":
13405
+ case "data_dir_conflict":
13406
+ case "data_dir_invalid":
13407
+ case "identity_mismatch":
13408
+ case "instance_not_found":
13409
+ case "lock_not_owned":
13410
+ case "name_invalid":
13411
+ case "port_conflict":
13412
+ case "port_invalid":
13413
+ case "record_invalid":
13414
+ case "self_lifecycle_unsupported":
13415
+ return false;
13416
+ }
13417
+ }
13418
+ function instanceErrorOutput(error) {
13419
+ return { schemaVersion: INSTANCE_API_SCHEMA_VERSION, error };
13339
13420
  }
13340
13421
  function envString(name2) {
13341
13422
  const value = process.env[name2];
@@ -13370,6 +13451,7 @@ function setCurrentContext(patch) {
13370
13451
  };
13371
13452
  return currentContext;
13372
13453
  }
13454
+ const MCP_INSTANCE_WRITES_ENV = "AGENT_INSPECTOR_MCP_INSTANCE_WRITES";
13373
13455
  function parseFlag(value) {
13374
13456
  if (value === void 0) return null;
13375
13457
  switch (value.trim().toLowerCase()) {
@@ -13393,6 +13475,20 @@ function isMcpWriteEnabled() {
13393
13475
  const writesFlag = parseFlag(process.env["AGENT_INSPECTOR_MCP_WRITES"]);
13394
13476
  return writesFlag === true;
13395
13477
  }
13478
+ function isMcpInstanceWriteEnabled() {
13479
+ return process.env[MCP_INSTANCE_WRITES_ENV] === "1";
13480
+ }
13481
+ function getMcpInstanceModeInfo() {
13482
+ const writesEnabled = isMcpInstanceWriteEnabled();
13483
+ return {
13484
+ writeMode: writesEnabled ? "enabled" : "readonly",
13485
+ writesEnabled,
13486
+ env: {
13487
+ AGENT_INSPECTOR_MCP_INSTANCE_WRITES: process.env[MCP_INSTANCE_WRITES_ENV] ?? null
13488
+ },
13489
+ note: writesEnabled ? "Named-instance lifecycle tools passed the instance-specific opt-in. General MCP writes must also be enabled." : "Named-instance lifecycle tools require AGENT_INSPECTOR_MCP_INSTANCE_WRITES=1 in addition to general MCP writes."
13490
+ };
13491
+ }
13396
13492
  function getMcpModeInfo() {
13397
13493
  const writesEnabled = isMcpWriteEnabled();
13398
13494
  return {
@@ -13405,6 +13501,95 @@ function getMcpModeInfo() {
13405
13501
  note: writesEnabled ? "MCP write/action tools are enabled explicitly by AGENT_INSPECTOR_MCP_WRITES=1." : "MCP is readonly by default. Read tools/resources still work; set AGENT_INSPECTOR_MCP_WRITES=1 to enable mutations."
13406
13502
  };
13407
13503
  }
13504
+ const INSTANCE_LIFECYCLE_TIMEOUT_MS = 6e4;
13505
+ const InstanceToolNameSchema = string().trim().min(1).max(64);
13506
+ const InstanceLifecycleToolInputSchema = InstanceStartRequestSchema.extend({
13507
+ name: InstanceToolNameSchema
13508
+ });
13509
+ const InstanceNameToolInputSchema = object({
13510
+ name: InstanceToolNameSchema
13511
+ }).strict();
13512
+ function textJson$1(data) {
13513
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
13514
+ }
13515
+ function toolError$1(message) {
13516
+ return { content: [{ type: "text", text: message }], isError: true };
13517
+ }
13518
+ async function responseJson$1(response) {
13519
+ try {
13520
+ const value = await response.json();
13521
+ return value;
13522
+ } catch {
13523
+ return null;
13524
+ }
13525
+ }
13526
+ async function validatedInstanceResponse(response, schema, operation) {
13527
+ const value = await responseJson$1(response);
13528
+ if (!response.ok) {
13529
+ const error = InstanceErrorOutputSchema.safeParse(value);
13530
+ return error.success ? { ...textJson$1(error.data), isError: true } : toolError$1(
13531
+ `${operation} returned HTTP ${String(response.status)} with an invalid error body`
13532
+ );
13533
+ }
13534
+ const parsed = schema.safeParse(value);
13535
+ return parsed.success ? textJson$1(parsed.data) : toolError$1(`${operation} returned an invalid public instance document`);
13536
+ }
13537
+ function instancePath(name2, suffix = "") {
13538
+ return `/api/instances/${encodeURIComponent(name2)}${suffix}`;
13539
+ }
13540
+ function jsonPost(body) {
13541
+ return {
13542
+ method: "POST",
13543
+ headers: {
13544
+ accept: "application/json",
13545
+ "content-type": "application/json"
13546
+ },
13547
+ body: JSON.stringify(body),
13548
+ timeoutMs: INSTANCE_LIFECYCLE_TIMEOUT_MS
13549
+ };
13550
+ }
13551
+ function lifecycleRequest(input) {
13552
+ return {
13553
+ port: input.port,
13554
+ basePath: input.basePath,
13555
+ host: input.host,
13556
+ captureMode: input.captureMode,
13557
+ dataDir: input.dataDir
13558
+ };
13559
+ }
13560
+ async function listInstancesImpl(callApi2) {
13561
+ const response = await callApi2("/api/instances", {
13562
+ headers: { accept: "application/json" }
13563
+ });
13564
+ return validatedInstanceResponse(response, InstanceListOutputSchema, "GET /api/instances");
13565
+ }
13566
+ async function getInstanceImpl(callApi2, name2) {
13567
+ const path2 = instancePath(name2);
13568
+ const response = await callApi2(path2, { headers: { accept: "application/json" } });
13569
+ return validatedInstanceResponse(response, InstanceStatusOutputSchema, `GET ${path2}`);
13570
+ }
13571
+ async function getInstanceConnectionImpl(callApi2, name2) {
13572
+ const path2 = instancePath(name2, "/connection");
13573
+ const response = await callApi2(path2, { headers: { accept: "application/json" } });
13574
+ return validatedInstanceResponse(response, InstanceConnectionOutputSchema, `GET ${path2}`);
13575
+ }
13576
+ async function startInstanceImpl(callApi2, input) {
13577
+ const path2 = instancePath(input.name, "/start");
13578
+ const request = lifecycleRequest(input);
13579
+ const response = await callApi2(path2, jsonPost(InstanceStartRequestSchema.parse(request)));
13580
+ return validatedInstanceResponse(response, InstanceOperationOutputSchema, `POST ${path2}`);
13581
+ }
13582
+ async function stopInstanceImpl(callApi2, name2) {
13583
+ const path2 = instancePath(name2, "/stop");
13584
+ const response = await callApi2(path2, jsonPost(InstanceEmptyRequestSchema.parse({})));
13585
+ return validatedInstanceResponse(response, InstanceOperationOutputSchema, `POST ${path2}`);
13586
+ }
13587
+ async function restartInstanceImpl(callApi2, input) {
13588
+ const path2 = instancePath(input.name, "/restart");
13589
+ const request = lifecycleRequest(input);
13590
+ const response = await callApi2(path2, jsonPost(InstanceStartRequestSchema.parse(request)));
13591
+ return validatedInstanceResponse(response, InstanceOperationOutputSchema, `POST ${path2}`);
13592
+ }
13408
13593
  function groupEvidenceDir(groupId) {
13409
13594
  return join(getDataDir(), "evidence", "groups", groupId);
13410
13595
  }
@@ -13774,9 +13959,16 @@ async function callApi(path2, options = {}) {
13774
13959
  if (!path2.startsWith("/")) {
13775
13960
  throw new Error(`callApi: path must start with '/', got: ${path2}`);
13776
13961
  }
13777
- const port = getCurrentPort();
13778
- const url = `http://127.0.0.1:${port}${withBasePath(path2, getConfiguredBasePath(process.env))}`;
13962
+ const port = getPublicPort();
13963
+ const publicBasePath = getPublicBasePath();
13964
+ const url2 = `http://127.0.0.1:${port}${withBasePath(path2, publicBasePath)}`;
13779
13965
  const { timeoutMs = DEFAULT_TIMEOUT_MS, signal: userSignal, ...rest } = options;
13966
+ const headers = new Headers(rest.headers);
13967
+ headers.set(
13968
+ AGENT_INSPECTOR_PUBLIC_BASE_PATH_HEADER,
13969
+ publicBasePath.length === 0 ? "/" : publicBasePath
13970
+ );
13971
+ headers.set(AGENT_INSPECTOR_PUBLIC_PORT_HEADER, String(port));
13780
13972
  const controller = new AbortController();
13781
13973
  const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
13782
13974
  if (userSignal !== void 0 && userSignal !== null) {
@@ -13787,7 +13979,7 @@ async function callApi(path2, options = {}) {
13787
13979
  }
13788
13980
  }
13789
13981
  try {
13790
- return await fetch(url, { ...rest, signal: controller.signal });
13982
+ return await fetch(url2, { ...rest, headers, signal: controller.signal });
13791
13983
  } catch (err) {
13792
13984
  if (err instanceof Error && err.name === "AbortError") {
13793
13985
  throw new LoopbackTimeoutError(path2, timeoutMs);
@@ -13995,7 +14187,7 @@ function redactedProvidersResult(value) {
13995
14187
  return textJson(toRedactedProviderDtos(parsed.data));
13996
14188
  }
13997
14189
  function inspectorBaseUrl() {
13998
- return `http://127.0.0.1:${String(getCurrentPort())}`;
14190
+ return `http://127.0.0.1:${String(getPublicPort())}`;
13999
14191
  }
14000
14192
  function hasBodyText(value, byteLength) {
14001
14193
  if (value !== null && value.length > 0) return true;
@@ -14527,8 +14719,8 @@ async function diagnoseCaptureImpl(callApi2, args = {}) {
14527
14719
  runtimePayload = JSON.parse(runtimeText);
14528
14720
  } catch {
14529
14721
  }
14530
- const runtimeRecord = isRecord(runtimePayload) ? runtimePayload : {};
14531
- const configRecord = isRecord(runtimeRecord["config"]) ? runtimeRecord["config"] : {};
14722
+ const runtimeRecord = isRecord$2(runtimePayload) ? runtimePayload : {};
14723
+ const configRecord = isRecord$2(runtimeRecord["config"]) ? runtimeRecord["config"] : {};
14532
14724
  const captureMode = stringField(configRecord, "captureMode");
14533
14725
  let log = null;
14534
14726
  if (args.id !== void 0) {
@@ -14850,11 +15042,11 @@ function collectProviderDiagnosticIssues(value, path2, issues) {
14850
15042
  );
14851
15043
  return;
14852
15044
  }
14853
- if (!isRecord(value)) return;
14854
- const success = value["success"];
15045
+ if (!isRecord$2(value)) return;
15046
+ const success2 = value["success"];
14855
15047
  const status = firstNumberField(value, ["status", "responseStatus", "statusCode"]);
14856
15048
  const error = firstStringField(value, ["error", "message", "errorMessage"]);
14857
- if (success === false || error !== null || status !== null && status >= 400) {
15049
+ if (success2 === false || error !== null || status !== null && status >= 400) {
14858
15050
  issues.push({
14859
15051
  path: path2,
14860
15052
  status,
@@ -15055,14 +15247,10 @@ async function getServer() {
15055
15247
  return initPromise;
15056
15248
  }
15057
15249
  async function handleMcpRequest(request) {
15058
- try {
15059
- const url = new URL(request.url);
15060
- const port = Number(url.port);
15061
- if (port > 0) setCurrentPort(port);
15062
- } catch {
15063
- }
15064
- const { transport } = await getServer();
15065
- return transport.handleRequest(request);
15250
+ return runWithRequestPublicBasePath(request, async () => {
15251
+ const { transport } = await getServer();
15252
+ return transport.handleRequest(request);
15253
+ });
15066
15254
  }
15067
15255
  const TOOL_LIST_LOGS_DESC = `List recent captured agent/model proxy logs in reverse-chronological order with parsed previews. Useful for "what did I just send?" discovery.
15068
15256
 
@@ -15084,6 +15272,22 @@ Returns: array of "thick summary" objects, each containing:
15084
15272
 
15085
15273
  Either preview field is null when the body is unknown format, unparseable, or the relevant content is non-text (e.g., image-only).`;
15086
15274
  const PROVIDER_WRITE_WARNING = "⚠ This tool mutates provider configuration. Confirm with the user before invoking.";
15275
+ const INSTANCE_LIFECYCLE_WRITE_WARNING = "This tool changes a local Agent Inspector process. Obtain explicit user approval before invoking it.";
15276
+ const INSTANCE_READ_TOOL_NAMES = [
15277
+ "inspector_list_instances",
15278
+ "inspector_get_instance",
15279
+ "inspector_get_instance_connection"
15280
+ ];
15281
+ const INSTANCE_WRITE_TOOL_NAMES = [
15282
+ "inspector_start_instance",
15283
+ "inspector_stop_instance",
15284
+ "inspector_restart_instance"
15285
+ ];
15286
+ const INSTANCE_RESOURCE_URIS = [
15287
+ "inspector://instances",
15288
+ "inspector://instances/{name}",
15289
+ "inspector://instances/{name}/connection"
15290
+ ];
15087
15291
  const AddProviderInputSchema = object({
15088
15292
  name: string().min(1).describe("Provider display name."),
15089
15293
  apiKey: string().min(1).describe("Plaintext provider API key."),
@@ -15132,9 +15336,9 @@ function jsonResource(uri, data) {
15132
15336
  return textResource(uri, "application/json", JSON.stringify(data, null, 2));
15133
15337
  }
15134
15338
  function mcpEndpointUrl() {
15135
- return `http://localhost:${String(getCurrentPort())}${withBasePath(
15339
+ return `http://localhost:${String(getPublicPort())}${withBasePath(
15136
15340
  "/api/mcp",
15137
- getConfiguredBasePath(process.env)
15341
+ getPublicBasePath()
15138
15342
  )}`;
15139
15343
  }
15140
15344
  function mcpHealth() {
@@ -15146,7 +15350,7 @@ function mcpHealth() {
15146
15350
  },
15147
15351
  transport: {
15148
15352
  primary: "streamable-http",
15149
- endpoint: withBasePath("/api/mcp", getConfiguredBasePath(process.env)),
15353
+ endpoint: mcpEndpointUrl(),
15150
15354
  stateless: true
15151
15355
  },
15152
15356
  mode: getMcpModeInfo(),
@@ -15158,6 +15362,7 @@ function mcpHealth() {
15158
15362
  };
15159
15363
  }
15160
15364
  const WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
15365
+ ...INSTANCE_WRITE_TOOL_NAMES,
15161
15366
  "inspector_create_run",
15162
15367
  "inspector_update_run",
15163
15368
  "inspector_export_evidence",
@@ -15181,42 +15386,59 @@ const WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
15181
15386
  function mcpCapabilities() {
15182
15387
  const readTools = TOOL_NAMES.filter((name2) => !WRITE_TOOL_NAMES.has(name2));
15183
15388
  const writeTools = TOOL_NAMES.filter((name2) => WRITE_TOOL_NAMES.has(name2));
15389
+ const generalWriteMode = getMcpModeInfo();
15390
+ const instanceWriteMode = getMcpInstanceModeInfo();
15184
15391
  return {
15185
15392
  serverInfo: {
15186
15393
  name: "agent-inspector",
15187
15394
  version: MCP_SERVER_VERSION
15188
15395
  },
15189
- mode: getMcpModeInfo(),
15396
+ mode: generalWriteMode,
15190
15397
  tools: {
15191
15398
  read: readTools,
15192
15399
  writeOrAction: writeTools
15193
15400
  },
15194
15401
  resources: RESOURCE_NAMES,
15195
- prompts: PROMPT_NAMES
15402
+ prompts: PROMPT_NAMES,
15403
+ instanceControl: {
15404
+ tools: {
15405
+ read: INSTANCE_READ_TOOL_NAMES,
15406
+ writeOrAction: INSTANCE_WRITE_TOOL_NAMES
15407
+ },
15408
+ resources: INSTANCE_RESOURCE_URIS,
15409
+ writeGates: {
15410
+ general: generalWriteMode,
15411
+ instance: instanceWriteMode,
15412
+ lifecycleWritesEnabled: generalWriteMode.writesEnabled && instanceWriteMode.writesEnabled
15413
+ },
15414
+ limitations: {
15415
+ selfStopOrRestart: "The serving managed instance cannot stop or restart itself over REST or MCP. Use the CLI or a sibling controller instance."
15416
+ }
15417
+ }
15196
15418
  };
15197
15419
  }
15198
15420
  function mcpConfig() {
15199
- const endpoint = mcpEndpointUrl();
15421
+ const endpoint2 = mcpEndpointUrl();
15200
15422
  return {
15201
15423
  streamableHttp: {
15202
- endpoint,
15424
+ endpoint: endpoint2,
15203
15425
  config: {
15204
15426
  mcpServers: {
15205
15427
  "agent-inspector": {
15206
15428
  type: "streamableHttp",
15207
- url: endpoint
15429
+ url: endpoint2
15208
15430
  }
15209
15431
  }
15210
15432
  }
15211
15433
  },
15212
15434
  stdioBridge: {
15213
15435
  command: "agent-inspector-mcp",
15214
- args: ["stdio", "--url", endpoint],
15436
+ args: ["stdio", "--url", endpoint2],
15215
15437
  config: {
15216
15438
  mcpServers: {
15217
15439
  "agent-inspector": {
15218
15440
  command: "agent-inspector-mcp",
15219
- args: ["stdio", "--url", endpoint]
15441
+ args: ["stdio", "--url", endpoint2]
15220
15442
  }
15221
15443
  }
15222
15444
  }
@@ -15225,7 +15447,7 @@ function mcpConfig() {
15225
15447
  mcp: {
15226
15448
  "agent-inspector": {
15227
15449
  type: "local",
15228
- command: ["agent-inspector-mcp", "stdio", "--url", endpoint],
15450
+ command: ["agent-inspector-mcp", "stdio", "--url", endpoint2],
15229
15451
  enabled: true
15230
15452
  }
15231
15453
  }
@@ -15234,7 +15456,7 @@ function mcpConfig() {
15234
15456
  mcp: {
15235
15457
  "agent-inspector": {
15236
15458
  type: "local",
15237
- command: ["agent-inspector-mcp", "stdio", "--url", endpoint],
15459
+ command: ["agent-inspector-mcp", "stdio", "--url", endpoint2],
15238
15460
  enabled: true
15239
15461
  }
15240
15462
  }
@@ -15267,6 +15489,32 @@ function safeWriteCall(toolName, fn) {
15267
15489
  return fn();
15268
15490
  });
15269
15491
  }
15492
+ function disabledInstanceWriteTool(toolName) {
15493
+ return {
15494
+ content: [
15495
+ {
15496
+ type: "text",
15497
+ text: JSON.stringify(
15498
+ {
15499
+ error: "mcp-instance-write-disabled",
15500
+ tool: toolName,
15501
+ generalMode: getMcpModeInfo(),
15502
+ instanceMode: getMcpInstanceModeInfo()
15503
+ },
15504
+ null,
15505
+ 2
15506
+ )
15507
+ }
15508
+ ],
15509
+ isError: true
15510
+ };
15511
+ }
15512
+ function safeInstanceWriteCall(toolName, fn) {
15513
+ return safeWriteCall(
15514
+ toolName,
15515
+ () => isMcpInstanceWriteEnabled() ? fn() : disabledInstanceWriteTool(toolName)
15516
+ );
15517
+ }
15270
15518
  function variableString(variables, name2) {
15271
15519
  const value = variables[name2];
15272
15520
  if (Array.isArray(value)) return value[0] ?? null;
@@ -15291,6 +15539,32 @@ function readServiceJsonResource(uri, result) {
15291
15539
  if (!result.ok) return textResource(uri, "text/plain", result.message);
15292
15540
  return jsonResource(uri, result.value);
15293
15541
  }
15542
+ async function readInstanceToolResource(uri, resultPromise) {
15543
+ const result = await resultPromise;
15544
+ const text = result.content[0]?.text ?? "";
15545
+ return textResource(uri, result.isError === true ? "text/plain" : "application/json", text);
15546
+ }
15547
+ async function listInstanceTemplateResources(connection) {
15548
+ try {
15549
+ const response = await callApi("/api/instances", {
15550
+ headers: { accept: "application/json" }
15551
+ });
15552
+ if (!response.ok) return listResult([]);
15553
+ const parsed = InstanceListOutputSchema.safeParse(await response.json());
15554
+ if (!parsed.success) return listResult([]);
15555
+ return listResult(
15556
+ parsed.data.instances.map((instance) => ({
15557
+ uri: connection ? `inspector://instances/${encodeURIComponent(instance.name)}/connection` : `inspector://instances/${encodeURIComponent(instance.name)}`,
15558
+ name: connection ? `instance-connection:${instance.name}` : `instance:${instance.name}`,
15559
+ title: connection ? `Agent Inspector connection for ${instance.name}` : `Agent Inspector instance ${instance.name}`,
15560
+ mimeType: "application/json",
15561
+ description: `${instance.state} at ${instance.urls.ui}`
15562
+ }))
15563
+ );
15564
+ } catch {
15565
+ return listResult([]);
15566
+ }
15567
+ }
15294
15568
  async function listSessionResources() {
15295
15569
  try {
15296
15570
  const response = await callApi("/api/sessions");
@@ -15467,6 +15741,60 @@ function userPrompt(text) {
15467
15741
  };
15468
15742
  }
15469
15743
  function registerTools(server) {
15744
+ server.registerTool(
15745
+ "inspector_list_instances",
15746
+ {
15747
+ title: "List named Agent Inspector instances",
15748
+ description: "Returns the versioned, token-free REST instance list with live state, saved configuration, and public URLs. Available in readonly mode.",
15749
+ inputSchema: object({}).strict()
15750
+ },
15751
+ () => safeCall(() => listInstancesImpl(callApi))
15752
+ );
15753
+ server.registerTool(
15754
+ "inspector_get_instance",
15755
+ {
15756
+ title: "Get a named Agent Inspector instance",
15757
+ description: "Returns one versioned, token-free named-instance status document from the REST control plane. Available in readonly mode.",
15758
+ inputSchema: InstanceNameToolInputSchema
15759
+ },
15760
+ ({ name: name2 }) => safeCall(() => getInstanceImpl(callApi, name2))
15761
+ );
15762
+ server.registerTool(
15763
+ "inspector_get_instance_connection",
15764
+ {
15765
+ title: "Get coding-agent connection settings for an instance",
15766
+ description: "Returns the REST connection descriptor for one named instance, including protocol-correct proxy, OpenAI /v1, MCP, health, environment, and Codex values. It never includes credentials.",
15767
+ inputSchema: InstanceNameToolInputSchema
15768
+ },
15769
+ ({ name: name2 }) => safeCall(() => getInstanceConnectionImpl(callApi, name2))
15770
+ );
15771
+ server.registerTool(
15772
+ "inspector_start_instance",
15773
+ {
15774
+ title: "Start or create a named Agent Inspector instance",
15775
+ description: `${INSTANCE_LIFECYCLE_WRITE_WARNING} Starts, creates, or idempotently reuses a named sibling instance through the REST lifecycle API. Requires both AGENT_INSPECTOR_MCP_WRITES=1 and AGENT_INSPECTOR_MCP_INSTANCE_WRITES=1.`,
15776
+ inputSchema: InstanceLifecycleToolInputSchema
15777
+ },
15778
+ (args) => safeInstanceWriteCall("inspector_start_instance", () => startInstanceImpl(callApi, args))
15779
+ );
15780
+ server.registerTool(
15781
+ "inspector_stop_instance",
15782
+ {
15783
+ title: "Stop a named Agent Inspector instance",
15784
+ description: `${INSTANCE_LIFECYCLE_WRITE_WARNING} Gracefully stops a sibling instance after authenticated ownership checks. The instance serving this MCP connection cannot stop itself. Requires both MCP write gates.`,
15785
+ inputSchema: InstanceNameToolInputSchema
15786
+ },
15787
+ ({ name: name2 }) => safeInstanceWriteCall("inspector_stop_instance", () => stopInstanceImpl(callApi, name2))
15788
+ );
15789
+ server.registerTool(
15790
+ "inspector_restart_instance",
15791
+ {
15792
+ title: "Restart a named Agent Inspector instance",
15793
+ description: `${INSTANCE_LIFECYCLE_WRITE_WARNING} Validates and restarts a sibling instance through the bounded REST lifecycle path. The instance serving this MCP connection cannot restart itself. Requires both MCP write gates.`,
15794
+ inputSchema: InstanceLifecycleToolInputSchema
15795
+ },
15796
+ (args) => safeInstanceWriteCall("inspector_restart_instance", () => restartInstanceImpl(callApi, args))
15797
+ );
15470
15798
  server.registerTool(
15471
15799
  "inspector_list_logs",
15472
15800
  {
@@ -16012,6 +16340,46 @@ PATCH-style update: only the fields you supply are changed. Use models to update
16012
16340
  );
16013
16341
  }
16014
16342
  function registerResources(server) {
16343
+ server.registerResource(
16344
+ "inspector_instances",
16345
+ "inspector://instances",
16346
+ {
16347
+ title: "Named Agent Inspector instances",
16348
+ description: "Versioned, token-free named-instance list backed by GET /api/instances.",
16349
+ mimeType: "application/json"
16350
+ },
16351
+ (uri) => readInstanceToolResource(uri, listInstancesImpl(callApi))
16352
+ );
16353
+ server.registerResource(
16354
+ "inspector_instance",
16355
+ new ResourceTemplate("inspector://instances/{name}", {
16356
+ list: async () => await listInstanceTemplateResources(false)
16357
+ }),
16358
+ {
16359
+ title: "Named Agent Inspector instance",
16360
+ description: "Versioned, token-free status for one named instance backed by GET /api/instances/{name}.",
16361
+ mimeType: "application/json"
16362
+ },
16363
+ (uri, variables) => {
16364
+ const name2 = variableString(variables, "name");
16365
+ return name2 === null ? textResource(uri, "text/plain", "Missing instance name") : readInstanceToolResource(uri, getInstanceImpl(callApi, name2));
16366
+ }
16367
+ );
16368
+ server.registerResource(
16369
+ "inspector_instance_connection",
16370
+ new ResourceTemplate("inspector://instances/{name}/connection", {
16371
+ list: async () => await listInstanceTemplateResources(true)
16372
+ }),
16373
+ {
16374
+ title: "Named instance coding-agent connection",
16375
+ description: "Token-free connection descriptor backed by GET /api/instances/{name}/connection.",
16376
+ mimeType: "application/json"
16377
+ },
16378
+ (uri, variables) => {
16379
+ const name2 = variableString(variables, "name");
16380
+ return name2 === null ? textResource(uri, "text/plain", "Missing instance name") : readInstanceToolResource(uri, getInstanceConnectionImpl(callApi, name2));
16381
+ }
16382
+ );
16015
16383
  server.registerResource(
16016
16384
  "inspector_mcp_health",
16017
16385
  "inspector://mcp/health",
@@ -16456,6 +16824,8 @@ Return:
16456
16824
  );
16457
16825
  }
16458
16826
  const TOOL_NAMES = [
16827
+ ...INSTANCE_READ_TOOL_NAMES,
16828
+ ...INSTANCE_WRITE_TOOL_NAMES,
16459
16829
  "inspector_list_logs",
16460
16830
  "inspector_search_logs",
16461
16831
  "inspector_get_log",
@@ -16503,6 +16873,9 @@ const TOOL_NAMES = [
16503
16873
  "inspector_get_project_context"
16504
16874
  ];
16505
16875
  const RESOURCE_NAMES = [
16876
+ "inspector_instances",
16877
+ "inspector_instance",
16878
+ "inspector_instance_connection",
16506
16879
  "inspector_mcp_health",
16507
16880
  "inspector_mcp_capabilities",
16508
16881
  "inspector_mcp_config",
@@ -16533,7 +16906,7 @@ const PROMPT_NAMES = [
16533
16906
  "inspector_generate_group_report",
16534
16907
  "inspector_extract_repro_steps"
16535
16908
  ];
16536
- const Route$D = createFileRoute("/api/mcp")({
16909
+ const Route$J = createFileRoute("/api/mcp")({
16537
16910
  server: {
16538
16911
  handlers: {
16539
16912
  // The SDK may issue either POST, GET, or DELETE. TanStack Start only
@@ -16646,15 +17019,15 @@ function parseOptionalPositiveInt(value) {
16646
17019
  if (!Number.isInteger(parsed) || parsed < 1) return { ok: false };
16647
17020
  return { ok: true, value: parsed };
16648
17021
  }
16649
- const Route$C = createFileRoute("/api/logs")({
17022
+ const Route$I = createFileRoute("/api/logs")({
16650
17023
  server: {
16651
17024
  handlers: {
16652
17025
  GET: async ({ request }) => {
16653
- const url = new URL(request.url);
16654
- if (url.searchParams.get("stats") === "1") {
17026
+ const url2 = new URL(request.url);
17027
+ if (url2.searchParams.get("stats") === "1") {
16655
17028
  return Response.json(getLogStorageStats());
16656
17029
  }
16657
- const replayOf = url.searchParams.get("replayOf");
17030
+ const replayOf = url2.searchParams.get("replayOf");
16658
17031
  if (replayOf !== null) {
16659
17032
  const id = Number(replayOf);
16660
17033
  if (!Number.isInteger(id) || id <= 0) {
@@ -16663,15 +17036,15 @@ const Route$C = createFileRoute("/api/logs")({
16663
17036
  const logs = getReplayLogsForSource(id);
16664
17037
  return Response.json({ logs, total: logs.length, offset: 0, limit: logs.length });
16665
17038
  }
16666
- const sessionId = url.searchParams.get("sessionId") ?? void 0;
16667
- const model = url.searchParams.get("model") ?? void 0;
16668
- const clientPidResult = parseOptionalPositiveInt(url.searchParams.get("clientPid"));
17039
+ const sessionId = url2.searchParams.get("sessionId") ?? void 0;
17040
+ const model = url2.searchParams.get("model") ?? void 0;
17041
+ const clientPidResult = parseOptionalPositiveInt(url2.searchParams.get("clientPid"));
16669
17042
  if (!clientPidResult.ok) {
16670
17043
  return Response.json({ error: "Invalid clientPid" }, { status: 400 });
16671
17044
  }
16672
17045
  const clientPid = clientPidResult.value ?? void 0;
16673
- const query = url.searchParams.get("q") ?? url.searchParams.get("search");
16674
- const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
17046
+ const query = url2.searchParams.get("q") ?? url2.searchParams.get("search");
17047
+ const offset = parseNonNegativeInt(url2.searchParams.get("offset"), 0);
16675
17048
  if (query !== null) {
16676
17049
  if (query.length > MAX_SEARCH_QUERY_CHARS) {
16677
17050
  return resourceLimitResponse({
@@ -16684,7 +17057,7 @@ const Route$C = createFileRoute("/api/logs")({
16684
17057
  });
16685
17058
  }
16686
17059
  const limitResult2 = parseBoundedIntegerParameter({
16687
- value: url.searchParams.get("limit"),
17060
+ value: url2.searchParams.get("limit"),
16688
17061
  parameter: "limit",
16689
17062
  fallback: LOG_SEARCH_DEFAULT_LIMIT,
16690
17063
  minimum: 1,
@@ -16693,7 +17066,7 @@ const Route$C = createFileRoute("/api/logs")({
16693
17066
  });
16694
17067
  if (!limitResult2.ok) return limitResult2.response;
16695
17068
  const scanLimitResult = parseBoundedIntegerParameter({
16696
- value: url.searchParams.get("scanLimit"),
17069
+ value: url2.searchParams.get("scanLimit"),
16697
17070
  parameter: "scanLimit",
16698
17071
  fallback: LOG_SEARCH_DEFAULT_SCAN_LIMIT,
16699
17072
  minimum: 1,
@@ -16714,7 +17087,7 @@ const Route$C = createFileRoute("/api/logs")({
16714
17087
  );
16715
17088
  }
16716
17089
  const limitResult = parseBoundedIntegerParameter({
16717
- value: url.searchParams.get("limit"),
17090
+ value: url2.searchParams.get("limit"),
16718
17091
  parameter: "limit",
16719
17092
  fallback: 50,
16720
17093
  minimum: 1,
@@ -16723,10 +17096,10 @@ const Route$C = createFileRoute("/api/logs")({
16723
17096
  });
16724
17097
  if (!limitResult.ok) return limitResult.response;
16725
17098
  const limit = limitResult.value;
16726
- const includeBodies = url.searchParams.get("compact") !== "1";
16727
- if (url.searchParams.get("cursor") === "1" || url.searchParams.get("cursor") === "true") {
16728
- const beforeLogId = parseOptionalPositiveInt(url.searchParams.get("beforeLogId"));
16729
- const afterLogId = parseOptionalPositiveInt(url.searchParams.get("afterLogId"));
17099
+ const includeBodies = url2.searchParams.get("compact") !== "1";
17100
+ if (url2.searchParams.get("cursor") === "1" || url2.searchParams.get("cursor") === "true") {
17101
+ const beforeLogId = parseOptionalPositiveInt(url2.searchParams.get("beforeLogId"));
17102
+ const afterLogId = parseOptionalPositiveInt(url2.searchParams.get("afterLogId"));
16730
17103
  if (!beforeLogId.ok || !afterLogId.ok) {
16731
17104
  return Response.json({ error: "Invalid cursor log ID" }, { status: 400 });
16732
17105
  }
@@ -16736,7 +17109,7 @@ const Route$C = createFileRoute("/api/logs")({
16736
17109
  { status: 400 }
16737
17110
  );
16738
17111
  }
16739
- const anchor = url.searchParams.get("anchor") === "oldest" ? "oldest" : "newest";
17112
+ const anchor = url2.searchParams.get("anchor") === "oldest" ? "oldest" : "newest";
16740
17113
  return Response.json(
16741
17114
  await listLogsCursorPage({
16742
17115
  sessionId,
@@ -16803,94 +17176,1549 @@ const Route$C = createFileRoute("/api/logs")({
16803
17176
  }
16804
17177
  }
16805
17178
  });
16806
- function createShutdownCoordinator(dependencies, deadlineMs) {
16807
- let shutdownPromise = null;
16808
- async function shutdown(_reason = "manual") {
16809
- if (shutdownPromise !== null) return await shutdownPromise;
16810
- dependencies.markShuttingDown();
16811
- dependencies.stopAdmission();
16812
- let forced = false;
16813
- let forceClosed = false;
16814
- let deadline = null;
16815
- function forceCloseOnce() {
16816
- if (forceClosed) return;
16817
- forceClosed = true;
16818
- dependencies.forceClose();
16819
- }
16820
- async function gracefulShutdown() {
16821
- try {
16822
- await dependencies.drainTraffic();
16823
- if (forced) return { forced: true, reason: "deadline" };
16824
- await dependencies.drainFinalizers();
16825
- if (forced) return { forced: true, reason: "deadline" };
16826
- await dependencies.flushPersistence();
16827
- if (forced) return { forced: true, reason: "deadline" };
16828
- await dependencies.closeResources();
16829
- return { forced: false, reason: "completed" };
16830
- } catch {
16831
- forceCloseOnce();
16832
- return { forced: true, reason: "error" };
16833
- }
16834
- }
16835
- const timedOut = new Promise((resolve2) => {
16836
- deadline = setTimeout(
16837
- () => {
16838
- forced = true;
16839
- forceCloseOnce();
16840
- resolve2({ forced: true, reason: "deadline" });
16841
- },
16842
- Math.max(1, deadlineMs)
16843
- );
16844
- });
16845
- shutdownPromise = Promise.race([gracefulShutdown(), timedOut]).finally(() => {
16846
- if (deadline !== null) clearTimeout(deadline);
16847
- });
16848
- return await shutdownPromise;
16849
- }
16850
- return { shutdown };
17179
+ const MANAGED_INSTANCE_CONTROL_PATH = "/.agent-inspector/instance";
17180
+ const MANAGED_INSTANCE_SHUTDOWN_PATH = `${MANAGED_INSTANCE_CONTROL_PATH}/shutdown`;
17181
+ const MANAGED_INSTANCE_TOKEN_HEADER = "x-agent-inspector-instance-token";
17182
+ const MANAGED_INSTANCE_SHUTDOWN_MESSAGE_TYPE = "agent-inspector:managed-shutdown";
17183
+ const AGENT_INSPECTOR_CLI_ENTRY_ENV = "AGENT_INSPECTOR_CLI_ENTRY";
17184
+ const MANAGED_INSTANCE_ENV = {
17185
+ name: "AGENT_INSPECTOR_INSTANCE_NAME",
17186
+ instanceId: "AGENT_INSPECTOR_INSTANCE_ID",
17187
+ launchId: "AGENT_INSPECTOR_INSTANCE_LAUNCH_ID",
17188
+ controlToken: "AGENT_INSPECTOR_INSTANCE_CONTROL_TOKEN",
17189
+ startedAt: "AGENT_INSPECTOR_INSTANCE_STARTED_AT",
17190
+ upstreamPort: "AGENT_INSPECTOR_UPSTREAM_PORT"
17191
+ };
17192
+ function nonEmpty(value) {
17193
+ const trimmed = value?.trim();
17194
+ return trimmed === void 0 || trimmed.length === 0 ? null : trimmed;
16851
17195
  }
16852
- function createShutdownSignalHandler(coordinator, onComplete) {
16853
- let handled = false;
16854
- return (signal) => {
16855
- if (handled) return;
16856
- handled = true;
16857
- void coordinator.shutdown(signal).then(onComplete);
17196
+ function isRecord$1(value) {
17197
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17198
+ }
17199
+ function readManagedInstanceLaunch(env = process.env) {
17200
+ const values = [
17201
+ env[MANAGED_INSTANCE_ENV.name],
17202
+ env[MANAGED_INSTANCE_ENV.instanceId],
17203
+ env[MANAGED_INSTANCE_ENV.launchId],
17204
+ env[MANAGED_INSTANCE_ENV.controlToken],
17205
+ env[MANAGED_INSTANCE_ENV.startedAt],
17206
+ env[MANAGED_INSTANCE_ENV.upstreamPort]
17207
+ ];
17208
+ if (values.every((value) => value === void 0 || value.trim().length === 0)) {
17209
+ return { kind: "unmanaged" };
17210
+ }
17211
+ const name2 = nonEmpty(env[MANAGED_INSTANCE_ENV.name]);
17212
+ const instanceId = nonEmpty(env[MANAGED_INSTANCE_ENV.instanceId]);
17213
+ const launchId = nonEmpty(env[MANAGED_INSTANCE_ENV.launchId]);
17214
+ const controlToken = nonEmpty(env[MANAGED_INSTANCE_ENV.controlToken]);
17215
+ const startedAt = nonEmpty(env[MANAGED_INSTANCE_ENV.startedAt]);
17216
+ const upstreamPort = Number(env[MANAGED_INSTANCE_ENV.upstreamPort]);
17217
+ if (name2 === null || instanceId === null || launchId === null || controlToken === null || controlToken.length < 32 || startedAt === null || !Number.isFinite(Date.parse(startedAt)) || !Number.isInteger(upstreamPort) || upstreamPort < 1 || upstreamPort > 65535) {
17218
+ return {
17219
+ kind: "invalid",
17220
+ message: "Managed instance launch environment is incomplete or invalid."
17221
+ };
17222
+ }
17223
+ return {
17224
+ kind: "managed",
17225
+ launch: { name: name2, instanceId, launchId, controlToken, startedAt, upstreamPort }
16858
17226
  };
16859
17227
  }
16860
- const DEFAULT_SHUTDOWN_DEADLINE_MS = 15e3;
16861
- function shutdownDeadlineMs() {
16862
- const raw = process.env["AGENT_INSPECTOR_SHUTDOWN_TIMEOUT_MS"];
16863
- if (raw === void 0 || raw === "") return DEFAULT_SHUTDOWN_DEADLINE_MS;
16864
- const parsed = Number(raw);
16865
- return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= 3e5 ? parsed : DEFAULT_SHUTDOWN_DEADLINE_MS;
17228
+ function parseManagedInstanceShutdownMessage(value) {
17229
+ if (!isRecord$1(value)) return null;
17230
+ return value["type"] === MANAGED_INSTANCE_SHUTDOWN_MESSAGE_TYPE && typeof value["controlToken"] === "string" ? { type: MANAGED_INSTANCE_SHUTDOWN_MESSAGE_TYPE, controlToken: value["controlToken"] } : null;
16866
17231
  }
16867
- async function drainFinalizers() {
16868
- await flushAllRawStreamCaptures();
16869
- await flushSessionTasks();
16870
- await flushToolSchemaWarningAnalysis();
17232
+ function platformCommand(command, args, platform = process.platform) {
17233
+ if (platform !== "win32") return { command, args: [...args] };
17234
+ return { command: "cmd.exe", args: ["/d", "/s", "/c", command, ...args] };
16871
17235
  }
16872
- async function flushPersistence() {
16873
- await flushLogBuffer();
16874
- await flushSessionArchiveWrites();
16875
- await flushIndex();
16876
- await flushApplicationLog();
17236
+ function npmCommand(platform = process.platform) {
17237
+ return platform === "win32" ? "npm.cmd" : "npm";
16877
17238
  }
16878
- async function closeResources() {
16879
- await closeLogFinalizerWorkers();
16880
- destroyAllSessionProcesses();
16881
- closeSqliteLogIndex();
16882
- await flushApplicationLog();
17239
+ function npmSpawnCommand(args, platform = process.platform) {
17240
+ return platformCommand(npmCommand(platform), args, platform);
16883
17241
  }
16884
- function forceCloseResources() {
16885
- forceCloseLogFinalizerWorkers();
16886
- destroyAllSessionProcesses();
16887
- closeSqliteLogIndex();
17242
+ function openUrlCommand(targetUrl, platform = process.platform) {
17243
+ switch (platform) {
17244
+ case "darwin":
17245
+ return { command: "open", args: [targetUrl] };
17246
+ case "linux":
17247
+ case "freebsd":
17248
+ case "openbsd":
17249
+ case "netbsd":
17250
+ return { command: "xdg-open", args: [targetUrl] };
17251
+ case "win32":
17252
+ return { command: "cmd.exe", args: ["/d", "/s", "/c", "start", "", targetUrl] };
17253
+ case "aix":
17254
+ case "android":
17255
+ case "cygwin":
17256
+ case "haiku":
17257
+ case "sunos":
17258
+ return null;
17259
+ }
17260
+ return null;
16888
17261
  }
16889
- const runtimeShutdownCoordinator = createShutdownCoordinator(
16890
- {
16891
- markShuttingDown: () => setRuntimeShuttingDown(true),
16892
- stopAdmission: stopRuntimeAdmission,
16893
- drainTraffic: waitForRuntimeTrafficDrain,
17262
+ function localUrlForPort(port) {
17263
+ return `http://localhost:${String(port)}`;
17264
+ }
17265
+ function trimHost(host) {
17266
+ const trimmed = host?.trim();
17267
+ return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
17268
+ }
17269
+ function isWildcardHost(host) {
17270
+ const trimmed = trimHost(host);
17271
+ return trimmed === void 0 || trimmed === "0.0.0.0" || trimmed === "::" || trimmed === "[::]";
17272
+ }
17273
+ function bracketIpv6(host) {
17274
+ if (!host.includes(":")) return host;
17275
+ if (host.startsWith("[") && host.endsWith("]")) return host;
17276
+ return `[${host}]`;
17277
+ }
17278
+ function urlForHost(port, host) {
17279
+ const trimmed = trimHost(host);
17280
+ if (trimmed === void 0 || isWildcardHost(trimmed)) return localUrlForPort(port);
17281
+ return `http://${bracketIpv6(trimmed)}:${String(port)}`;
17282
+ }
17283
+ function probeHostForBindHost(host) {
17284
+ const trimmed = trimHost(host);
17285
+ if (trimmed === void 0 || isWildcardHost(trimmed)) return "127.0.0.1";
17286
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed.slice(1, -1);
17287
+ return trimmed;
17288
+ }
17289
+ const DEFAULT_CONTROL_TIMEOUT_MS = 2e3;
17290
+ function isRecord(value) {
17291
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17292
+ }
17293
+ function parseIdentity(value) {
17294
+ if (!isRecord(value)) return null;
17295
+ const schemaVersion = value["schemaVersion"];
17296
+ const instanceId = value["instanceId"];
17297
+ const launchId = value["launchId"];
17298
+ const supervisorPid = value["supervisorPid"];
17299
+ const startedAt = value["startedAt"];
17300
+ const publicPort = value["publicPort"];
17301
+ const upstreamPort = value["upstreamPort"];
17302
+ if (schemaVersion !== 1 || typeof instanceId !== "string" || instanceId.length === 0 || typeof launchId !== "string" || launchId.length === 0 || typeof supervisorPid !== "number" || !Number.isInteger(supervisorPid) || supervisorPid < 1 || typeof startedAt !== "string" || !Number.isFinite(Date.parse(startedAt)) || typeof publicPort !== "number" || !Number.isInteger(publicPort) || publicPort < 1 || publicPort > 65535 || typeof upstreamPort !== "number" || !Number.isInteger(upstreamPort) || upstreamPort < 1 || upstreamPort > 65535) {
17303
+ return null;
17304
+ }
17305
+ return {
17306
+ schemaVersion: 1,
17307
+ instanceId,
17308
+ launchId,
17309
+ supervisorPid,
17310
+ startedAt,
17311
+ publicPort,
17312
+ upstreamPort
17313
+ };
17314
+ }
17315
+ function hostForUrl(host) {
17316
+ if (host.startsWith("[") && host.endsWith("]")) return host;
17317
+ return host.includes(":") ? `[${host}]` : host;
17318
+ }
17319
+ function endpoint(identity, path2) {
17320
+ return `http://${hostForUrl(identity.host)}:${String(identity.publicPort)}${path2}`;
17321
+ }
17322
+ function requestInit(identity, controller, method) {
17323
+ return {
17324
+ method,
17325
+ headers: {
17326
+ accept: "application/json",
17327
+ [MANAGED_INSTANCE_TOKEN_HEADER]: identity.controlToken
17328
+ },
17329
+ cache: "no-store",
17330
+ signal: controller.signal
17331
+ };
17332
+ }
17333
+ async function responseJson(response) {
17334
+ try {
17335
+ const value = await response.json();
17336
+ return value;
17337
+ } catch {
17338
+ return null;
17339
+ }
17340
+ }
17341
+ async function probeInstanceControl(expected, fetchImpl = fetch, timeoutMs = DEFAULT_CONTROL_TIMEOUT_MS) {
17342
+ const controller = new AbortController();
17343
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
17344
+ try {
17345
+ const response = await fetchImpl(
17346
+ endpoint(expected, MANAGED_INSTANCE_CONTROL_PATH),
17347
+ requestInit(expected, controller, "GET")
17348
+ );
17349
+ if (!response.ok) return { kind: "identity-mismatch" };
17350
+ const identity = parseIdentity(await responseJson(response));
17351
+ if (identity === null) return { kind: "invalid-response" };
17352
+ if (identity.instanceId !== expected.instanceId || identity.launchId !== expected.launchId || identity.publicPort !== expected.publicPort) {
17353
+ return { kind: "identity-mismatch" };
17354
+ }
17355
+ return { kind: "running", identity };
17356
+ } catch (error) {
17357
+ return {
17358
+ kind: "unreachable",
17359
+ timedOut: controller.signal.aborted || error instanceof Error && error.name === "AbortError"
17360
+ };
17361
+ } finally {
17362
+ clearTimeout(timeout);
17363
+ }
17364
+ }
17365
+ async function requestInstanceShutdown(expected, fetchImpl = fetch, timeoutMs = DEFAULT_CONTROL_TIMEOUT_MS) {
17366
+ const controller = new AbortController();
17367
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
17368
+ try {
17369
+ const response = await fetchImpl(
17370
+ endpoint(expected, MANAGED_INSTANCE_SHUTDOWN_PATH),
17371
+ requestInit(expected, controller, "POST")
17372
+ );
17373
+ if (response.status === 202) return { kind: "accepted" };
17374
+ if (response.status === 401 || response.status === 403 || response.status === 404) {
17375
+ return { kind: "identity-mismatch" };
17376
+ }
17377
+ return { kind: "rejected" };
17378
+ } catch (error) {
17379
+ return {
17380
+ kind: "unreachable",
17381
+ timedOut: controller.signal.aborted || error instanceof Error && error.name === "AbortError"
17382
+ };
17383
+ } finally {
17384
+ clearTimeout(timeout);
17385
+ }
17386
+ }
17387
+ const INSTANCE_RECORD_SCHEMA_VERSION = 1;
17388
+ const MAX_INSTANCE_NAME_LENGTH = 64;
17389
+ const WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/u;
17390
+ const INSTANCE_NAME_CHARACTERS = /^[a-z0-9._-]+$/u;
17391
+ function instanceRegistrySuccess(value) {
17392
+ return { kind: "success", value };
17393
+ }
17394
+ function instanceRegistryError(code, message) {
17395
+ return { kind: "error", error: { code, message } };
17396
+ }
17397
+ function validateInstanceName(rawName) {
17398
+ const normalized = rawName.toLowerCase();
17399
+ const invalid = rawName.length === 0 || rawName !== rawName.trim() || normalized.length > MAX_INSTANCE_NAME_LENGTH || normalized === "." || normalized === ".." || normalized === "default" || normalized.endsWith(".") || normalized.endsWith(" ") || !INSTANCE_NAME_CHARACTERS.test(normalized) || WINDOWS_DEVICE_NAME.test(normalized);
17400
+ return invalid ? instanceRegistryError(
17401
+ "name_invalid",
17402
+ `Invalid instance name ${JSON.stringify(rawName)}. Use 1-${String(MAX_INSTANCE_NAME_LENGTH)} letters, digits, dots, hyphens, or underscores; "default" and Windows device names are reserved.`
17403
+ ) : instanceRegistrySuccess(normalized);
17404
+ }
17405
+ function normalizeInstanceBasePath(rawBasePath) {
17406
+ const value = rawBasePath ?? "";
17407
+ const trimmed = value.trim();
17408
+ const hasControlCharacter = [...trimmed].some((character) => {
17409
+ const codePoint = character.codePointAt(0) ?? 0;
17410
+ return codePoint < 32 || codePoint === 127;
17411
+ });
17412
+ if (trimmed.length > 0 && (!trimmed.startsWith("/") || trimmed.includes("?") || trimmed.includes("#") || trimmed.includes("\\") || hasControlCharacter)) {
17413
+ return instanceRegistryError(
17414
+ "record_invalid",
17415
+ "Instance Base Path must be an absolute URL path without a query, hash, backslash, or control character."
17416
+ );
17417
+ }
17418
+ const normalized = normalizeBasePath(trimmed);
17419
+ const reservedControlRoot = MANAGED_INSTANCE_CONTROL_PATH.replace(/\/instance$/u, "");
17420
+ if (normalized === reservedControlRoot || normalized.startsWith(`${reservedControlRoot}/`)) {
17421
+ return instanceRegistryError(
17422
+ "record_invalid",
17423
+ `Instance Base Path ${normalized} collides with the reserved Agent Inspector control namespace.`
17424
+ );
17425
+ }
17426
+ return instanceRegistrySuccess(normalized);
17427
+ }
17428
+ const NormalizedInstanceNameSchema = string().refine((name2) => {
17429
+ const result = validateInstanceName(name2);
17430
+ return result.kind === "success" && result.value === name2;
17431
+ });
17432
+ const NormalizedBasePathSchema = string().refine((basePath) => {
17433
+ const result = normalizeInstanceBasePath(basePath);
17434
+ return result.kind === "success" && result.value === basePath;
17435
+ });
17436
+ const PortSchema = number().int().min(1).max(65535);
17437
+ const TimestampSchema = string().datetime();
17438
+ const IdentifierSchema = string().min(8).max(128);
17439
+ const InstanceLaunchSchema = object({
17440
+ launchId: IdentifierSchema,
17441
+ controlToken: string().min(32).max(256),
17442
+ startedAt: TimestampSchema
17443
+ }).strict();
17444
+ const InstanceRecordSchema = object({
17445
+ schemaVersion: literal(INSTANCE_RECORD_SCHEMA_VERSION),
17446
+ name: NormalizedInstanceNameSchema,
17447
+ instanceId: IdentifierSchema,
17448
+ createdAt: TimestampSchema,
17449
+ updatedAt: TimestampSchema,
17450
+ host: string().trim().min(1).max(255),
17451
+ publicPort: PortSchema,
17452
+ upstreamPort: PortSchema,
17453
+ basePath: NormalizedBasePathSchema,
17454
+ captureMode: CaptureModeSchema,
17455
+ dataDir: string().min(1).refine((path2) => isAbsolute(path2)),
17456
+ launch: InstanceLaunchSchema
17457
+ }).strict().superRefine((record2, context) => {
17458
+ if (record2.publicPort === record2.upstreamPort) {
17459
+ context.addIssue({
17460
+ code: "custom",
17461
+ message: "Public and upstream ports must be different.",
17462
+ path: ["upstreamPort"]
17463
+ });
17464
+ }
17465
+ });
17466
+ function createLaunch(factory, now) {
17467
+ return {
17468
+ launchId: factory.createLaunchId?.() ?? randomUUID(),
17469
+ controlToken: factory.createControlToken?.() ?? randomBytes(32).toString("base64url"),
17470
+ startedAt: now.toISOString()
17471
+ };
17472
+ }
17473
+ function createInstanceRecord(input, factory = {}) {
17474
+ const name2 = validateInstanceName(input.name);
17475
+ if (name2.kind === "error") return name2;
17476
+ const basePath = normalizeInstanceBasePath(input.basePath);
17477
+ if (basePath.kind === "error") return basePath;
17478
+ const now = factory.now?.() ?? /* @__PURE__ */ new Date();
17479
+ const timestamp = now.toISOString();
17480
+ const candidate = {
17481
+ schemaVersion: INSTANCE_RECORD_SCHEMA_VERSION,
17482
+ name: name2.value,
17483
+ instanceId: factory.createInstanceId?.() ?? randomUUID(),
17484
+ createdAt: timestamp,
17485
+ updatedAt: timestamp,
17486
+ host: input.host.trim(),
17487
+ publicPort: input.publicPort,
17488
+ upstreamPort: input.upstreamPort,
17489
+ basePath: basePath.value,
17490
+ captureMode: input.captureMode,
17491
+ dataDir: input.dataDir,
17492
+ launch: createLaunch(factory, now)
17493
+ };
17494
+ const parsed = InstanceRecordSchema.safeParse(candidate);
17495
+ return parsed.success ? instanceRegistrySuccess(parsed.data) : instanceRegistryError(
17496
+ "record_invalid",
17497
+ `Cannot create instance record: ${parsed.error.issues[0]?.message ?? "invalid saved configuration"}`
17498
+ );
17499
+ }
17500
+ function rotateInstanceLaunch(record2, factory = {}) {
17501
+ const now = factory.now?.() ?? /* @__PURE__ */ new Date();
17502
+ const candidate = {
17503
+ ...record2,
17504
+ updatedAt: now.toISOString(),
17505
+ launch: createLaunch(factory, now)
17506
+ };
17507
+ const parsed = InstanceRecordSchema.safeParse(candidate);
17508
+ return parsed.success ? instanceRegistrySuccess(parsed.data) : instanceRegistryError(
17509
+ "record_invalid",
17510
+ `Cannot rotate instance launch: ${parsed.error.issues[0]?.message ?? "invalid saved configuration"}`
17511
+ );
17512
+ }
17513
+ const AGENT_INSPECTOR_INSTANCES_DIR_ENV = "AGENT_INSPECTOR_INSTANCES_DIR";
17514
+ const DEFAULT_NAMED_INSTANCE_PUBLIC_PORT = 9530;
17515
+ const NAMED_INSTANCE_PORT_STEP = 3;
17516
+ const NAMED_INSTANCE_UPSTREAM_OFFSET = 2;
17517
+ const DEFAULT_INSTANCE_LOCK_TIMEOUT_MS = 1e4;
17518
+ const DEFAULT_INSTANCE_LOCK_STALE_MS = 3e4;
17519
+ const INSTANCE_RECORD_FILE_NAME = "instance.json";
17520
+ const ROOT_LOCK_DIRECTORY_NAME = ".allocation.lock";
17521
+ const INSTANCE_LOCK_DIRECTORY_NAME = ".mutation.lock";
17522
+ const LOCK_OWNER_FILE_NAME = "owner.json";
17523
+ const DEFAULT_LOCK_RETRY_MS = 50;
17524
+ function getInstancesRoot(env = process.env, platform = process.platform) {
17525
+ const pathApi = platform === "win32" ? win32 : posix;
17526
+ const explicitRoot = env[AGENT_INSPECTOR_INSTANCES_DIR_ENV];
17527
+ if (explicitRoot !== void 0 && explicitRoot.trim().length > 0) {
17528
+ return pathApi.isAbsolute(explicitRoot) ? explicitRoot : pathApi.resolve(explicitRoot);
17529
+ }
17530
+ if (platform === "win32") {
17531
+ const localAppData = env["LOCALAPPDATA"];
17532
+ if (localAppData !== void 0 && localAppData.trim().length > 0) {
17533
+ return win32.join(localAppData, "agent-inspector", "instances");
17534
+ }
17535
+ const userProfile = env["USERPROFILE"];
17536
+ const fallback = userProfile !== void 0 && userProfile.trim().length > 0 ? userProfile : homedir();
17537
+ return win32.join(fallback, ".agent-inspector", "instances");
17538
+ }
17539
+ const home = env["HOME"];
17540
+ const base = home !== void 0 && home.trim().length > 0 ? home : homedir();
17541
+ return posix.join(base, ".agent-inspector", "instances");
17542
+ }
17543
+ function getInstancePaths(root, rawName) {
17544
+ const name2 = validateInstanceName(rawName);
17545
+ if (name2.kind === "error") return name2;
17546
+ const instanceDir = join(root, name2.value);
17547
+ return instanceRegistrySuccess({
17548
+ root,
17549
+ instanceDir,
17550
+ dataDir: join(instanceDir, "data"),
17551
+ recordPath: join(instanceDir, INSTANCE_RECORD_FILE_NAME),
17552
+ lockPath: join(instanceDir, INSTANCE_LOCK_DIRECTORY_NAME)
17553
+ });
17554
+ }
17555
+ function ensureInstancesRoot(root = getInstancesRoot()) {
17556
+ return ensurePrivateDirectorySync(root) ? instanceRegistrySuccess(root) : instanceRegistryError(
17557
+ "registry_io",
17558
+ `Cannot create or secure the private instance registry at ${root}.`
17559
+ );
17560
+ }
17561
+ function nodeErrorCode(error) {
17562
+ if (typeof error !== "object" || error === null) return null;
17563
+ const descriptor = Object.getOwnPropertyDescriptor(error, "code");
17564
+ return typeof descriptor?.value === "string" ? descriptor.value : null;
17565
+ }
17566
+ function readRecordFile(recordPath) {
17567
+ let parsedJson;
17568
+ try {
17569
+ parsedJson = JSON.parse(readFileSync(recordPath, "utf8"));
17570
+ } catch {
17571
+ return instanceRegistryError(
17572
+ "record_invalid",
17573
+ `Instance record ${recordPath} is unreadable or is not valid JSON.`
17574
+ );
17575
+ }
17576
+ const parsed = InstanceRecordSchema.safeParse(parsedJson);
17577
+ return parsed.success ? instanceRegistrySuccess(parsed.data) : instanceRegistryError(
17578
+ "record_invalid",
17579
+ `Instance record ${recordPath} does not match schema version 1: ${parsed.error.issues[0]?.message ?? "invalid record"}.`
17580
+ );
17581
+ }
17582
+ function readInstanceRecord(root, rawName) {
17583
+ const paths = getInstancePaths(root, rawName);
17584
+ if (paths.kind === "error") return paths;
17585
+ if (!existsSync(paths.value.recordPath)) return instanceRegistrySuccess(null);
17586
+ return readRecordFile(paths.value.recordPath);
17587
+ }
17588
+ function listInstanceRecords(root) {
17589
+ if (!existsSync(root)) return instanceRegistrySuccess([]);
17590
+ let entries;
17591
+ try {
17592
+ entries = readdirSync(root, { withFileTypes: true });
17593
+ } catch {
17594
+ return instanceRegistryError("registry_io", `Cannot read the instance registry at ${root}.`);
17595
+ }
17596
+ const records = [];
17597
+ const names = /* @__PURE__ */ new Set();
17598
+ for (const entry of entries) {
17599
+ if (!entry.isDirectory()) continue;
17600
+ const recordPath = join(root, entry.name, INSTANCE_RECORD_FILE_NAME);
17601
+ if (!existsSync(recordPath)) continue;
17602
+ const record2 = readRecordFile(recordPath);
17603
+ if (record2.kind === "error") return record2;
17604
+ const expectedName = validateInstanceName(entry.name);
17605
+ if (expectedName.kind === "error" || record2.value.name !== expectedName.value || names.has(record2.value.name)) {
17606
+ return instanceRegistryError(
17607
+ "record_invalid",
17608
+ `Instance directory ${entry.name} does not uniquely match its saved normalized name.`
17609
+ );
17610
+ }
17611
+ names.add(record2.value.name);
17612
+ records.push(record2.value);
17613
+ }
17614
+ records.sort((left, right) => left.name.localeCompare(right.name));
17615
+ return instanceRegistrySuccess(records);
17616
+ }
17617
+ function cleanupFile(path2) {
17618
+ try {
17619
+ rmSync(path2, { force: true });
17620
+ } catch {
17621
+ }
17622
+ }
17623
+ function writeInstanceRecord(root, record2) {
17624
+ const validated = InstanceRecordSchema.safeParse(record2);
17625
+ if (!validated.success) {
17626
+ return instanceRegistryError(
17627
+ "record_invalid",
17628
+ `Cannot save instance record: ${validated.error.issues[0]?.message ?? "invalid record"}.`
17629
+ );
17630
+ }
17631
+ const paths = getInstancePaths(root, validated.data.name);
17632
+ if (paths.kind === "error") return paths;
17633
+ const rootResult = ensureInstancesRoot(root);
17634
+ if (rootResult.kind === "error") return rootResult;
17635
+ if (!ensurePrivateDirectorySync(paths.value.instanceDir)) {
17636
+ return instanceRegistryError(
17637
+ "registry_io",
17638
+ `Cannot create or secure the private directory for instance ${validated.data.name}.`
17639
+ );
17640
+ }
17641
+ if (!ensurePrivateDirectorySync(validated.data.dataDir)) {
17642
+ return instanceRegistryError(
17643
+ "registry_io",
17644
+ `Cannot create or secure the data directory for instance ${validated.data.name}.`
17645
+ );
17646
+ }
17647
+ const temporaryPath = join(
17648
+ paths.value.instanceDir,
17649
+ `.${INSTANCE_RECORD_FILE_NAME}.${String(process.pid)}.${randomUUID()}.tmp`
17650
+ );
17651
+ let descriptor = null;
17652
+ try {
17653
+ descriptor = openSync(temporaryPath, "wx", PRIVATE_FILE_MODE);
17654
+ writeFileSync(descriptor, `${JSON.stringify(validated.data, null, 2)}
17655
+ `, "utf8");
17656
+ closeSync(descriptor);
17657
+ descriptor = null;
17658
+ if (!securePrivateFileSync(temporaryPath)) {
17659
+ cleanupFile(temporaryPath);
17660
+ return instanceRegistryError(
17661
+ "registry_io",
17662
+ `Cannot secure the saved record for instance ${validated.data.name}.`
17663
+ );
17664
+ }
17665
+ renameSync(temporaryPath, paths.value.recordPath);
17666
+ return instanceRegistrySuccess(validated.data);
17667
+ } catch {
17668
+ if (descriptor !== null) {
17669
+ try {
17670
+ closeSync(descriptor);
17671
+ } catch {
17672
+ }
17673
+ }
17674
+ cleanupFile(temporaryPath);
17675
+ return instanceRegistryError(
17676
+ "registry_io",
17677
+ `Cannot atomically save the record for instance ${validated.data.name}.`
17678
+ );
17679
+ }
17680
+ }
17681
+ const InstanceLockOwnerSchema = object({
17682
+ schemaVersion: literal(1),
17683
+ pid: number().int().positive(),
17684
+ token: string().min(8),
17685
+ createdAt: string().datetime()
17686
+ }).strict();
17687
+ function defaultSleep(milliseconds) {
17688
+ return new Promise((resolveSleep) => {
17689
+ setTimeout(resolveSleep, milliseconds);
17690
+ });
17691
+ }
17692
+ function defaultIsProcessAlive(pid) {
17693
+ if (pid === process.pid) return true;
17694
+ try {
17695
+ process.kill(pid, 0);
17696
+ return true;
17697
+ } catch (error) {
17698
+ return nodeErrorCode(error) !== "ESRCH";
17699
+ }
17700
+ }
17701
+ function readLockOwner(lockPath) {
17702
+ try {
17703
+ const raw = JSON.parse(readFileSync(join(lockPath, LOCK_OWNER_FILE_NAME), "utf8"));
17704
+ const parsed = InstanceLockOwnerSchema.safeParse(raw);
17705
+ return parsed.success ? parsed.data : null;
17706
+ } catch {
17707
+ return null;
17708
+ }
17709
+ }
17710
+ function lockCreatedAt(lockPath, owner) {
17711
+ if (owner !== null) return Date.parse(owner.createdAt);
17712
+ try {
17713
+ return statSync(lockPath).mtimeMs;
17714
+ } catch {
17715
+ return null;
17716
+ }
17717
+ }
17718
+ function recoverStaleLock(lockPath, staleAfterMs, now, isProcessAlive) {
17719
+ const owner = readLockOwner(lockPath);
17720
+ const createdAt = lockCreatedAt(lockPath, owner);
17721
+ if (createdAt === null || now - createdAt < staleAfterMs) return false;
17722
+ if (owner !== null && isProcessAlive(owner.pid)) return false;
17723
+ const recoveredPath = `${lockPath}.stale-${randomUUID()}`;
17724
+ try {
17725
+ renameSync(lockPath, recoveredPath);
17726
+ rmSync(recoveredPath, { recursive: true, force: true });
17727
+ return true;
17728
+ } catch {
17729
+ return false;
17730
+ }
17731
+ }
17732
+ function releaseDirectoryLock(lockPath, token) {
17733
+ if (!existsSync(lockPath)) return instanceRegistrySuccess(void 0);
17734
+ const owner = readLockOwner(lockPath);
17735
+ if (owner === null || owner.token !== token) {
17736
+ return instanceRegistryError(
17737
+ "lock_not_owned",
17738
+ `Lifecycle lock ${lockPath} is no longer owned by this command.`
17739
+ );
17740
+ }
17741
+ try {
17742
+ rmSync(lockPath, { recursive: true, force: true });
17743
+ return instanceRegistrySuccess(void 0);
17744
+ } catch {
17745
+ return instanceRegistryError("registry_io", `Cannot release lifecycle lock ${lockPath}.`);
17746
+ }
17747
+ }
17748
+ async function acquireDirectoryLock(lockPath, options) {
17749
+ const timeoutMs = options.timeoutMs ?? DEFAULT_INSTANCE_LOCK_TIMEOUT_MS;
17750
+ const retryDelayMs = options.retryDelayMs ?? DEFAULT_LOCK_RETRY_MS;
17751
+ const staleAfterMs = options.staleAfterMs ?? DEFAULT_INSTANCE_LOCK_STALE_MS;
17752
+ const pid = options.pid ?? process.pid;
17753
+ const now = options.now ?? Date.now;
17754
+ const sleep2 = options.sleep ?? defaultSleep;
17755
+ const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive;
17756
+ const createToken = options.createToken ?? randomUUID;
17757
+ const startedAt = now();
17758
+ while (now() - startedAt <= timeoutMs) {
17759
+ const token = createToken();
17760
+ try {
17761
+ mkdirSync(lockPath, { mode: 448 });
17762
+ } catch (error) {
17763
+ if (nodeErrorCode(error) !== "EEXIST") {
17764
+ return instanceRegistryError("registry_io", `Cannot acquire lifecycle lock ${lockPath}.`);
17765
+ }
17766
+ if (recoverStaleLock(lockPath, staleAfterMs, now(), isProcessAlive)) continue;
17767
+ if (now() - startedAt >= timeoutMs) break;
17768
+ await sleep2(retryDelayMs);
17769
+ continue;
17770
+ }
17771
+ try {
17772
+ if (!ensurePrivateDirectorySync(lockPath)) {
17773
+ rmSync(lockPath, { recursive: true, force: true });
17774
+ return instanceRegistryError("registry_io", `Cannot secure lifecycle lock ${lockPath}.`);
17775
+ }
17776
+ const owner = {
17777
+ schemaVersion: 1,
17778
+ pid,
17779
+ token,
17780
+ createdAt: new Date(now()).toISOString()
17781
+ };
17782
+ const ownerPath = join(lockPath, LOCK_OWNER_FILE_NAME);
17783
+ writeFileSync(ownerPath, `${JSON.stringify(owner)}
17784
+ `, {
17785
+ encoding: "utf8",
17786
+ flag: "wx",
17787
+ mode: PRIVATE_FILE_MODE
17788
+ });
17789
+ if (!securePrivateFileSync(ownerPath)) {
17790
+ rmSync(lockPath, { recursive: true, force: true });
17791
+ return instanceRegistryError("registry_io", `Cannot secure lifecycle lock ${lockPath}.`);
17792
+ }
17793
+ return instanceRegistrySuccess({
17794
+ path: lockPath,
17795
+ release: () => releaseDirectoryLock(lockPath, token)
17796
+ });
17797
+ } catch {
17798
+ try {
17799
+ rmSync(lockPath, { recursive: true, force: true });
17800
+ } catch {
17801
+ }
17802
+ return instanceRegistryError("registry_io", `Cannot acquire lifecycle lock ${lockPath}.`);
17803
+ }
17804
+ }
17805
+ return instanceRegistryError(
17806
+ "lock_timeout",
17807
+ `Timed out waiting for lifecycle lock ${lockPath}; retry after the other command finishes.`
17808
+ );
17809
+ }
17810
+ async function acquireRegistryLock(root, options = {}) {
17811
+ const ensured = ensureInstancesRoot(root);
17812
+ return ensured.kind === "error" ? ensured : acquireDirectoryLock(join(root, ROOT_LOCK_DIRECTORY_NAME), options);
17813
+ }
17814
+ async function acquireInstanceLock(root, rawName, options = {}) {
17815
+ const paths = getInstancePaths(root, rawName);
17816
+ if (paths.kind === "error") return paths;
17817
+ const ensured = ensureInstancesRoot(root);
17818
+ if (ensured.kind === "error") return ensured;
17819
+ if (!ensurePrivateDirectorySync(paths.value.instanceDir)) {
17820
+ return instanceRegistryError(
17821
+ "registry_io",
17822
+ `Cannot create or secure the private directory for instance ${rawName}.`
17823
+ );
17824
+ }
17825
+ return acquireDirectoryLock(paths.value.lockPath, options);
17826
+ }
17827
+ function pathApiForPlatform(platform) {
17828
+ return platform === "win32" ? win32 : posix;
17829
+ }
17830
+ function resolveRealPathWithMissingTail(absolutePath, pathApi, realpath) {
17831
+ let current = absolutePath;
17832
+ const missingSegments = [];
17833
+ while (true) {
17834
+ try {
17835
+ return pathApi.join(realpath(current), ...missingSegments.reverse());
17836
+ } catch {
17837
+ const parent = pathApi.dirname(current);
17838
+ if (parent === current) return absolutePath;
17839
+ missingSegments.push(pathApi.basename(current));
17840
+ current = parent;
17841
+ }
17842
+ }
17843
+ }
17844
+ function canonicalizeDataDirectory(rawPath, options = {}) {
17845
+ if (rawPath.trim().length === 0 || rawPath.includes("\0")) {
17846
+ return instanceRegistryError("data_dir_invalid", "Instance data directory cannot be empty.");
17847
+ }
17848
+ const platform = options.platform ?? process.platform;
17849
+ const pathApi = pathApiForPlatform(platform);
17850
+ const cwd = options.cwd ?? process.cwd();
17851
+ const absolutePath = pathApi.resolve(cwd, rawPath);
17852
+ const resolvedPath = resolveRealPathWithMissingTail(
17853
+ absolutePath,
17854
+ pathApi,
17855
+ options.realpath ?? realpathSync.native
17856
+ );
17857
+ const normalizedPath = pathApi.normalize(resolvedPath);
17858
+ const root = pathApi.parse(normalizedPath).root;
17859
+ const withoutTrailingSeparator = normalizedPath === root ? normalizedPath : normalizedPath.replace(/[\\/]+$/u, "");
17860
+ return instanceRegistrySuccess({
17861
+ path: withoutTrailingSeparator,
17862
+ comparisonKey: platform === "win32" ? withoutTrailingSeparator.toLowerCase() : withoutTrailingSeparator
17863
+ });
17864
+ }
17865
+ function validateDataDirectoryAssignment(rawPath, records, excludeName, options = {}) {
17866
+ const candidate = canonicalizeDataDirectory(rawPath, options);
17867
+ if (candidate.kind === "error") return candidate;
17868
+ const normalizedExcludedName = excludeName?.toLowerCase();
17869
+ for (const record2 of records) {
17870
+ if (record2.name === normalizedExcludedName) continue;
17871
+ const registered = canonicalizeDataDirectory(record2.dataDir, options);
17872
+ if (registered.kind === "error") {
17873
+ return instanceRegistryError(
17874
+ "data_dir_conflict",
17875
+ `Cannot safely compare the data directory registered to instance ${record2.name}.`
17876
+ );
17877
+ }
17878
+ if (registered.value.comparisonKey === candidate.value.comparisonKey) {
17879
+ return instanceRegistryError(
17880
+ "data_dir_conflict",
17881
+ `Data directory ${candidate.value.path} is already assigned to instance ${record2.name}; named instances cannot share data.`
17882
+ );
17883
+ }
17884
+ }
17885
+ return candidate;
17886
+ }
17887
+ function validPort(port) {
17888
+ return Number.isInteger(port) && port >= 1 && port <= 65535;
17889
+ }
17890
+ function registeredPortOwner(pair, records, excludeName) {
17891
+ const excluded = excludeName?.toLowerCase();
17892
+ for (const record2 of records) {
17893
+ if (record2.name === excluded) continue;
17894
+ const occupied = /* @__PURE__ */ new Set([record2.publicPort, record2.upstreamPort]);
17895
+ if (occupied.has(pair.publicPort) || occupied.has(pair.upstreamPort)) return record2.name;
17896
+ }
17897
+ return null;
17898
+ }
17899
+ function isPortAvailableByBinding(port, host) {
17900
+ return new Promise((resolveAvailability) => {
17901
+ const server = createServer();
17902
+ let settled = false;
17903
+ const finish = (available) => {
17904
+ if (settled) return;
17905
+ settled = true;
17906
+ server.removeAllListeners();
17907
+ resolveAvailability(available);
17908
+ };
17909
+ server.once("error", () => finish(false));
17910
+ server.once("listening", () => {
17911
+ server.close((error) => finish(error === void 0));
17912
+ });
17913
+ server.unref();
17914
+ try {
17915
+ server.listen({ port, host, exclusive: true });
17916
+ } catch {
17917
+ finish(false);
17918
+ }
17919
+ });
17920
+ }
17921
+ async function pairIsAvailable(pair, publicHost, check) {
17922
+ if (!await check(pair.publicPort, publicHost)) {
17923
+ return { available: false, conflictingPort: pair.publicPort };
17924
+ }
17925
+ if (!await check(pair.upstreamPort, "127.0.0.1")) {
17926
+ return { available: false, conflictingPort: pair.upstreamPort };
17927
+ }
17928
+ return { available: true, conflictingPort: null };
17929
+ }
17930
+ async function planInstancePorts(options) {
17931
+ const check = options.isPortAvailable ?? isPortAvailableByBinding;
17932
+ const publicHost = options.publicHost ?? "127.0.0.1";
17933
+ if (options.requestedPublicPort === void 0 && options.requestedUpstreamPort !== void 0) {
17934
+ return instanceRegistryError(
17935
+ "port_invalid",
17936
+ "An explicit upstream port requires an explicit public port."
17937
+ );
17938
+ }
17939
+ if (options.requestedPublicPort !== void 0) {
17940
+ const pair = {
17941
+ publicPort: options.requestedPublicPort,
17942
+ upstreamPort: options.requestedUpstreamPort ?? options.requestedPublicPort + NAMED_INSTANCE_UPSTREAM_OFFSET
17943
+ };
17944
+ if (!validPort(pair.publicPort) || !validPort(pair.upstreamPort) || pair.publicPort === pair.upstreamPort) {
17945
+ return instanceRegistryError(
17946
+ "port_invalid",
17947
+ "Public and upstream ports must be different integers from 1 to 65535."
17948
+ );
17949
+ }
17950
+ const owner = registeredPortOwner(pair, options.records, options.excludeName);
17951
+ if (owner !== null) {
17952
+ return instanceRegistryError(
17953
+ "port_conflict",
17954
+ `Requested port pair ${String(pair.publicPort)}/${String(pair.upstreamPort)} overlaps instance ${owner}.`
17955
+ );
17956
+ }
17957
+ const availability = await pairIsAvailable(pair, publicHost, check);
17958
+ return availability.available ? instanceRegistrySuccess(pair) : instanceRegistryError(
17959
+ "port_conflict",
17960
+ `Port ${String(availability.conflictingPort)} already has a listener; no process was terminated.`
17961
+ );
17962
+ }
17963
+ for (let publicPort = DEFAULT_NAMED_INSTANCE_PUBLIC_PORT; publicPort + NAMED_INSTANCE_UPSTREAM_OFFSET <= 65535; publicPort += NAMED_INSTANCE_PORT_STEP) {
17964
+ const pair = {
17965
+ publicPort,
17966
+ upstreamPort: publicPort + NAMED_INSTANCE_UPSTREAM_OFFSET
17967
+ };
17968
+ if (registeredPortOwner(pair, options.records, options.excludeName) !== null) continue;
17969
+ const availability = await pairIsAvailable(pair, publicHost, check);
17970
+ if (availability.available) return instanceRegistrySuccess(pair);
17971
+ }
17972
+ return instanceRegistryError(
17973
+ "port_exhausted",
17974
+ `No available named-instance port pair was found from ${String(DEFAULT_NAMED_INSTANCE_PUBLIC_PORT)} through 65535.`
17975
+ );
17976
+ }
17977
+ const DEFAULT_INSTANCE_HOST = "127.0.0.1";
17978
+ const DEFAULT_INSTANCE_CAPTURE_MODE = "simple";
17979
+ const INSTANCE_READY_TIMEOUT_MS = 15e3;
17980
+ const INSTANCE_STOP_TIMEOUT_MS = 2e4;
17981
+ const INSTANCE_POLL_INTERVAL_MS = 200;
17982
+ function success(value) {
17983
+ return { kind: "success", value };
17984
+ }
17985
+ function failure(code, message) {
17986
+ return {
17987
+ kind: "error",
17988
+ error: { code, message, retryable: isRetryableInstanceError(code) }
17989
+ };
17990
+ }
17991
+ function fromRegistry(result) {
17992
+ return result.kind === "success" ? success(result.value) : failure(result.error.code, result.error.message);
17993
+ }
17994
+ function sleep(milliseconds) {
17995
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, milliseconds));
17996
+ }
17997
+ function displayBasePath(basePath) {
17998
+ return basePath.length === 0 ? "/" : basePath;
17999
+ }
18000
+ function recordUrls(record2) {
18001
+ const origin = urlForHost(record2.publicPort, record2.host);
18002
+ return {
18003
+ ui: appendBasePathToOrigin(origin, "/", record2.basePath),
18004
+ api: appendBasePathToOrigin(origin, "/api", record2.basePath),
18005
+ health: appendBasePathToOrigin(origin, "/api/health", record2.basePath),
18006
+ proxy: appendBasePathToOrigin(origin, "/proxy", record2.basePath),
18007
+ openai: appendBasePathToOrigin(origin, "/proxy/v1", record2.basePath),
18008
+ mcp: appendBasePathToOrigin(origin, "/api/mcp", record2.basePath)
18009
+ };
18010
+ }
18011
+ function statusOutput(record2, live, checkedAt = /* @__PURE__ */ new Date()) {
18012
+ return {
18013
+ schemaVersion: INSTANCE_API_SCHEMA_VERSION,
18014
+ name: record2.name,
18015
+ instanceId: record2.instanceId,
18016
+ state: live.state,
18017
+ stateReason: live.state === "conflict" ? live.code : null,
18018
+ checkedAt: checkedAt.toISOString(),
18019
+ createdAt: record2.createdAt,
18020
+ updatedAt: record2.updatedAt,
18021
+ launch: {
18022
+ launchId: record2.launch.launchId,
18023
+ startedAt: record2.launch.startedAt
18024
+ },
18025
+ host: record2.host,
18026
+ publicPort: record2.publicPort,
18027
+ upstreamPort: record2.upstreamPort,
18028
+ basePath: displayBasePath(record2.basePath),
18029
+ captureMode: record2.captureMode,
18030
+ dataDir: record2.dataDir,
18031
+ supervisorPid: live.supervisorPid,
18032
+ urls: recordUrls(record2)
18033
+ };
18034
+ }
18035
+ function operationOutput(operation, outcome, instance) {
18036
+ return {
18037
+ schemaVersion: INSTANCE_API_SCHEMA_VERSION,
18038
+ operation,
18039
+ outcome,
18040
+ instance
18041
+ };
18042
+ }
18043
+ function connectionOutput(instance) {
18044
+ const serverName = `agent-inspector-${instance.name}`;
18045
+ return {
18046
+ schemaVersion: INSTANCE_API_SCHEMA_VERSION,
18047
+ instance,
18048
+ baseUrl: instance.urls.ui,
18049
+ endpoints: instance.urls,
18050
+ environment: {
18051
+ ANTHROPIC_BASE_URL: instance.urls.proxy,
18052
+ LLM_BASE_URL: instance.urls.proxy,
18053
+ OPENAI_BASE_URL: instance.urls.openai,
18054
+ AGENT_INSPECTOR_MCP_URL: instance.urls.mcp
18055
+ },
18056
+ mcp: {
18057
+ serverName,
18058
+ transport: "streamable-http",
18059
+ url: instance.urls.mcp
18060
+ },
18061
+ codex: {
18062
+ providerName: serverName,
18063
+ baseUrl: instance.urls.openai,
18064
+ wireApi: "responses"
18065
+ }
18066
+ };
18067
+ }
18068
+ function expectedIdentity(record2) {
18069
+ return {
18070
+ instanceId: record2.instanceId,
18071
+ launchId: record2.launch.launchId,
18072
+ controlToken: record2.launch.controlToken,
18073
+ host: probeHostForBindHost(record2.host),
18074
+ publicPort: record2.publicPort
18075
+ };
18076
+ }
18077
+ async function classifyRecord(record2, deps) {
18078
+ const probe = await probeInstanceControl(expectedIdentity(record2), deps.fetchImpl);
18079
+ if (probe.kind === "running") {
18080
+ return { state: "running", supervisorPid: probe.identity.supervisorPid };
18081
+ }
18082
+ if (probe.kind === "identity-mismatch" || probe.kind === "invalid-response") {
18083
+ return { state: "conflict", supervisorPid: null, code: "identity_mismatch" };
18084
+ }
18085
+ const check = deps.isPortAvailable ?? isPortAvailableByBinding;
18086
+ const publicAvailable = await check(record2.publicPort, record2.host);
18087
+ const upstreamAvailable = await check(record2.upstreamPort, DEFAULT_INSTANCE_HOST);
18088
+ return publicAvailable && upstreamAvailable ? { state: "stopped", supervisorPid: null } : { state: "conflict", supervisorPid: null, code: "port_conflict" };
18089
+ }
18090
+ function waitForProcess(child) {
18091
+ return new Promise((resolveExit) => {
18092
+ let settled = false;
18093
+ const finish = (code) => {
18094
+ if (settled) return;
18095
+ settled = true;
18096
+ resolveExit(code);
18097
+ };
18098
+ child.once("exit", (code) => finish(code ?? 1));
18099
+ child.once("error", () => finish(1));
18100
+ });
18101
+ }
18102
+ function defaultOpenUrl(targetUrl) {
18103
+ const command = openUrlCommand(targetUrl);
18104
+ if (command === null) return;
18105
+ const child = spawn(command.command, command.args, {
18106
+ stdio: "ignore",
18107
+ detached: true,
18108
+ windowsHide: true
18109
+ });
18110
+ child.once("error", () => void 0);
18111
+ child.unref();
18112
+ }
18113
+ function launchArgs(record2, open2) {
18114
+ const args = [
18115
+ "--background",
18116
+ "--no-open",
18117
+ "--port",
18118
+ String(record2.publicPort),
18119
+ "--host",
18120
+ record2.host,
18121
+ "--mode",
18122
+ record2.captureMode
18123
+ ];
18124
+ if (open2) args.push("--open");
18125
+ return args;
18126
+ }
18127
+ async function defaultLaunch(record2, open2, cliEntry) {
18128
+ const child = spawn(process.execPath, [cliEntry, ...launchArgs(record2, open2)], {
18129
+ stdio: "ignore",
18130
+ windowsHide: true,
18131
+ env: {
18132
+ ...process.env,
18133
+ [AGENT_INSPECTOR_CLI_ENTRY_ENV]: cliEntry,
18134
+ AGENT_INSPECTOR_DATA_DIR: record2.dataDir,
18135
+ [AGENT_INSPECTOR_BASE_PATH_ENV]: displayBasePath(record2.basePath),
18136
+ [MANAGED_INSTANCE_ENV.name]: record2.name,
18137
+ [MANAGED_INSTANCE_ENV.instanceId]: record2.instanceId,
18138
+ [MANAGED_INSTANCE_ENV.launchId]: record2.launch.launchId,
18139
+ [MANAGED_INSTANCE_ENV.controlToken]: record2.launch.controlToken,
18140
+ [MANAGED_INSTANCE_ENV.startedAt]: record2.launch.startedAt,
18141
+ [MANAGED_INSTANCE_ENV.upstreamPort]: String(record2.upstreamPort)
18142
+ }
18143
+ });
18144
+ return await waitForProcess(child) === 0;
18145
+ }
18146
+ async function launchRecord(record2, open2, deps) {
18147
+ const cliEntry = deps.cliEntry ?? process.env[AGENT_INSPECTOR_CLI_ENTRY_ENV] ?? process.argv[1];
18148
+ if (deps.launch === void 0 && (cliEntry === void 0 || cliEntry.length === 0)) {
18149
+ return failure("launch_unavailable", "Cannot resolve the packaged Agent Inspector CLI entry.");
18150
+ }
18151
+ const launched = deps.launch === void 0 ? await defaultLaunch(record2, open2, cliEntry ?? "") : await deps.launch(record2, open2);
18152
+ if (!launched) {
18153
+ return failure(
18154
+ "launch_failed",
18155
+ `Instance ${record2.name} did not become ready; its saved configuration is retained for retry.`
18156
+ );
18157
+ }
18158
+ const wait = deps.sleep ?? sleep;
18159
+ const deadline = Date.now() + (deps.readyTimeoutMs ?? INSTANCE_READY_TIMEOUT_MS);
18160
+ while (Date.now() <= deadline) {
18161
+ const live = await classifyRecord(record2, deps);
18162
+ if (live.state === "running") return success(live);
18163
+ if (live.state === "conflict") {
18164
+ return failure(
18165
+ live.code,
18166
+ `Instance ${record2.name} launch identity does not own its saved port pair; no process was terminated.`
18167
+ );
18168
+ }
18169
+ await wait(INSTANCE_POLL_INTERVAL_MS);
18170
+ }
18171
+ return failure(
18172
+ "launch_failed",
18173
+ `Instance ${record2.name} launch timed out; its saved configuration is retained for retry.`
18174
+ );
18175
+ }
18176
+ async function waitForPortsToClose(record2, deps) {
18177
+ const check = deps.isPortAvailable ?? isPortAvailableByBinding;
18178
+ const wait = deps.sleep ?? sleep;
18179
+ const deadline = Date.now() + (deps.stopTimeoutMs ?? INSTANCE_STOP_TIMEOUT_MS);
18180
+ while (Date.now() <= deadline) {
18181
+ const publicAvailable = await check(record2.publicPort, record2.host);
18182
+ const upstreamAvailable = await check(record2.upstreamPort, DEFAULT_INSTANCE_HOST);
18183
+ if (publicAvailable && upstreamAvailable) return true;
18184
+ await wait(INSTANCE_POLL_INTERVAL_MS);
18185
+ }
18186
+ return false;
18187
+ }
18188
+ async function stopRecord(record2, deps) {
18189
+ const live = await classifyRecord(record2, deps);
18190
+ if (live.state === "stopped") return success({ live, outcome: "already_stopped" });
18191
+ if (live.state === "conflict") {
18192
+ return failure(
18193
+ live.code,
18194
+ `Instance ${record2.name} does not own its saved port pair; refusing to stop another process.`
18195
+ );
18196
+ }
18197
+ const requested = await requestInstanceShutdown(expectedIdentity(record2), deps.fetchImpl);
18198
+ if (requested.kind === "identity-mismatch") {
18199
+ return failure(
18200
+ "identity_mismatch",
18201
+ `Instance ${record2.name} changed identity before shutdown; no process was terminated.`
18202
+ );
18203
+ }
18204
+ if (requested.kind !== "accepted") {
18205
+ return failure("shutdown_failed", `Instance ${record2.name} rejected the shutdown request.`);
18206
+ }
18207
+ return await waitForPortsToClose(record2, deps) ? success({
18208
+ live: { state: "stopped", supervisorPid: null },
18209
+ outcome: "stopped"
18210
+ }) : failure(
18211
+ "shutdown_failed",
18212
+ `Instance ${record2.name} did not stop before the shutdown deadline.`
18213
+ );
18214
+ }
18215
+ async function acquireLocks(root, name2, includeRegistry) {
18216
+ const registryResult = includeRegistry ? await acquireRegistryLock(root) : null;
18217
+ if (registryResult !== null && registryResult.kind === "error") {
18218
+ return fromRegistry(registryResult);
18219
+ }
18220
+ const registry2 = registryResult?.kind === "success" ? registryResult.value : null;
18221
+ const instanceResult = await acquireInstanceLock(root, name2);
18222
+ if (instanceResult.kind === "error") {
18223
+ registry2?.release();
18224
+ return fromRegistry(instanceResult);
18225
+ }
18226
+ return success({ registry: registry2, instance: instanceResult.value });
18227
+ }
18228
+ function releaseLocks(locks) {
18229
+ const instanceReleased = locks.instance.release();
18230
+ const registryReleased = locks.registry?.release() ?? instanceRegistrySuccess(void 0);
18231
+ if (instanceReleased.kind === "error") return fromRegistry(instanceReleased);
18232
+ return fromRegistry(registryReleased);
18233
+ }
18234
+ async function withLocks(root, name2, includeRegistry, operation) {
18235
+ const locks = await acquireLocks(root, name2, includeRegistry);
18236
+ if (locks.kind === "error") return locks;
18237
+ let result;
18238
+ try {
18239
+ result = await operation();
18240
+ } catch {
18241
+ result = failure("registry_io", "The named-instance lifecycle operation failed.");
18242
+ }
18243
+ const released = releaseLocks(locks.value);
18244
+ return result.kind === "success" && released.kind === "error" ? released : result;
18245
+ }
18246
+ function readRequiredRecord(root, name2) {
18247
+ const read = readInstanceRecord(root, name2);
18248
+ if (read.kind === "error") return fromRegistry(read);
18249
+ return read.value === null ? failure("instance_not_found", `Named instance ${name2} does not exist.`) : success(read.value);
18250
+ }
18251
+ function overridesDiffer(record2, action) {
18252
+ const { overrides } = action;
18253
+ if (overrides.port !== null && overrides.port !== record2.publicPort) return true;
18254
+ if (overrides.basePath !== null && overrides.basePath !== record2.basePath) return true;
18255
+ if (overrides.host !== null && overrides.host !== record2.host) return true;
18256
+ if (overrides.captureMode !== null && overrides.captureMode !== record2.captureMode) return true;
18257
+ if (overrides.dataDir !== null) {
18258
+ const requested = canonicalizeDataDirectory(overrides.dataDir);
18259
+ const saved = canonicalizeDataDirectory(record2.dataDir);
18260
+ if (requested.kind === "error" || saved.kind === "error" || requested.value.comparisonKey !== saved.value.comparisonKey) {
18261
+ return true;
18262
+ }
18263
+ }
18264
+ return false;
18265
+ }
18266
+ function updatedRecord(record2, action, pair, dataDir2) {
18267
+ const candidate = {
18268
+ ...record2,
18269
+ host: action.overrides.host ?? record2.host,
18270
+ publicPort: pair.publicPort,
18271
+ upstreamPort: pair.upstreamPort,
18272
+ basePath: action.overrides.basePath ?? record2.basePath,
18273
+ captureMode: action.overrides.captureMode ?? record2.captureMode,
18274
+ dataDir: dataDir2
18275
+ };
18276
+ const parsed = InstanceRecordSchema.safeParse(candidate);
18277
+ if (!parsed.success) {
18278
+ return failure(
18279
+ "record_invalid",
18280
+ `Cannot update instance ${record2.name}: ${parsed.error.issues[0]?.message ?? "invalid configuration"}.`
18281
+ );
18282
+ }
18283
+ return fromRegistry(rotateInstanceLaunch(parsed.data));
18284
+ }
18285
+ function saveRecord(root, record2) {
18286
+ return fromRegistry(writeInstanceRecord(root, record2));
18287
+ }
18288
+ function validateInstanceDataDirectory(rawPath, records, excludeName) {
18289
+ const assigned = validateDataDirectoryAssignment(rawPath, records, excludeName);
18290
+ if (assigned.kind === "error") return fromRegistry(assigned);
18291
+ const defaultDirectory = canonicalizeDataDirectory(resolveDataDir());
18292
+ if (defaultDirectory.kind === "error") return fromRegistry(defaultDirectory);
18293
+ if (assigned.value.comparisonKey === defaultDirectory.value.comparisonKey) {
18294
+ return failure(
18295
+ "data_dir_conflict",
18296
+ `Data directory ${assigned.value.path} belongs to the unmanaged default instance; named instances cannot share it.`
18297
+ );
18298
+ }
18299
+ return success(assigned.value.path);
18300
+ }
18301
+ async function createNewRecord(root, action, deps) {
18302
+ const recordsResult = listInstanceRecords(root);
18303
+ if (recordsResult.kind === "error") return fromRegistry(recordsResult);
18304
+ const pathsResult = getInstancePaths(root, action.name);
18305
+ if (pathsResult.kind === "error") return fromRegistry(pathsResult);
18306
+ const host = action.overrides.host ?? DEFAULT_INSTANCE_HOST;
18307
+ const pairResult = await planInstancePorts({
18308
+ records: recordsResult.value,
18309
+ requestedPublicPort: action.overrides.port ?? void 0,
18310
+ publicHost: host,
18311
+ isPortAvailable: deps.isPortAvailable
18312
+ });
18313
+ if (pairResult.kind === "error") return fromRegistry(pairResult);
18314
+ const requestedDataDir = action.overrides.dataDir ?? pathsResult.value.dataDir;
18315
+ const dataDirResult = validateInstanceDataDirectory(requestedDataDir, recordsResult.value);
18316
+ if (dataDirResult.kind === "error") return dataDirResult;
18317
+ const created = createInstanceRecord({
18318
+ name: action.name,
18319
+ host,
18320
+ publicPort: pairResult.value.publicPort,
18321
+ upstreamPort: pairResult.value.upstreamPort,
18322
+ basePath: action.overrides.basePath ?? getConfiguredBasePath(process.env),
18323
+ captureMode: action.overrides.captureMode ?? DEFAULT_INSTANCE_CAPTURE_MODE,
18324
+ dataDir: dataDirResult.value
18325
+ });
18326
+ return created.kind === "error" ? fromRegistry(created) : saveRecord(root, created.value);
18327
+ }
18328
+ async function prepareStoppedStart(root, record2, deps) {
18329
+ const records = listInstanceRecords(root);
18330
+ if (records.kind === "error") return fromRegistry(records);
18331
+ const pair = await planInstancePorts({
18332
+ records: records.value,
18333
+ requestedPublicPort: record2.publicPort,
18334
+ requestedUpstreamPort: record2.upstreamPort,
18335
+ excludeName: record2.name,
18336
+ publicHost: record2.host,
18337
+ isPortAvailable: deps.isPortAvailable
18338
+ });
18339
+ if (pair.kind === "error") return fromRegistry(pair);
18340
+ const dataDir2 = validateInstanceDataDirectory(record2.dataDir, records.value, record2.name);
18341
+ if (dataDir2.kind === "error") return dataDir2;
18342
+ const rotated = rotateInstanceLaunch({ ...record2, dataDir: dataDir2.value });
18343
+ return rotated.kind === "error" ? fromRegistry(rotated) : saveRecord(root, rotated.value);
18344
+ }
18345
+ async function startAction(root, action, deps) {
18346
+ return withLocks(root, action.name, true, async () => {
18347
+ const read = readInstanceRecord(root, action.name);
18348
+ if (read.kind === "error") return fromRegistry(read);
18349
+ if (read.value === null) {
18350
+ const created = await createNewRecord(root, action, deps);
18351
+ if (created.kind === "error") return created;
18352
+ const launched2 = await launchRecord(created.value, action.overrides.open, deps);
18353
+ return launched2.kind === "error" ? launched2 : success(operationOutput("start", "created", statusOutput(created.value, launched2.value)));
18354
+ }
18355
+ const record2 = read.value;
18356
+ if (overridesDiffer(record2, action)) {
18357
+ return failure(
18358
+ "config_mismatch",
18359
+ `Instance ${record2.name} already has saved configuration; use "agent-inspector instance restart ${record2.name}" with overrides to change it.`
18360
+ );
18361
+ }
18362
+ const live = await classifyRecord(record2, deps);
18363
+ if (live.state === "running") {
18364
+ if (action.overrides.open) (deps.openUrl ?? defaultOpenUrl)(recordUrls(record2).ui);
18365
+ return success(operationOutput("start", "already_running", statusOutput(record2, live)));
18366
+ }
18367
+ if (live.state === "conflict") {
18368
+ return failure(
18369
+ live.code,
18370
+ `Instance ${record2.name} does not own its saved port pair; no process was terminated.`
18371
+ );
18372
+ }
18373
+ const prepared = await prepareStoppedStart(root, record2, deps);
18374
+ if (prepared.kind === "error") return prepared;
18375
+ const launched = await launchRecord(prepared.value, action.overrides.open, deps);
18376
+ return launched.kind === "error" ? launched : success(operationOutput("start", "started", statusOutput(prepared.value, launched.value)));
18377
+ });
18378
+ }
18379
+ async function planRestartRecord(root, record2, action, wasRunning, deps) {
18380
+ const records = listInstanceRecords(root);
18381
+ if (records.kind === "error") return fromRegistry(records);
18382
+ const desiredPublicPort = action.overrides.port ?? record2.publicPort;
18383
+ const desiredUpstreamPort = desiredPublicPort + 2;
18384
+ const sameLivePair = wasRunning && desiredPublicPort === record2.publicPort && desiredUpstreamPort === record2.upstreamPort;
18385
+ let pair;
18386
+ if (sameLivePair) {
18387
+ pair = { publicPort: record2.publicPort, upstreamPort: record2.upstreamPort };
18388
+ } else {
18389
+ const planned = await planInstancePorts({
18390
+ records: records.value,
18391
+ requestedPublicPort: desiredPublicPort,
18392
+ requestedUpstreamPort: desiredUpstreamPort,
18393
+ excludeName: record2.name,
18394
+ publicHost: action.overrides.host ?? record2.host,
18395
+ isPortAvailable: deps.isPortAvailable
18396
+ });
18397
+ if (planned.kind === "error") return fromRegistry(planned);
18398
+ pair = planned.value;
18399
+ }
18400
+ const requestedDataDir = action.overrides.dataDir ?? record2.dataDir;
18401
+ const dataDir2 = validateInstanceDataDirectory(requestedDataDir, records.value, record2.name);
18402
+ if (dataDir2.kind === "error") return dataDir2;
18403
+ return updatedRecord(record2, action, pair, dataDir2.value);
18404
+ }
18405
+ async function rollbackRestart(root, previous, deps) {
18406
+ const rotated = rotateInstanceLaunch(previous);
18407
+ if (rotated.kind === "error") return false;
18408
+ const saved = saveRecord(root, rotated.value);
18409
+ if (saved.kind === "error") return false;
18410
+ const launched = await launchRecord(saved.value, false, deps);
18411
+ return launched.kind === "success";
18412
+ }
18413
+ async function restartFailureAfterStop(root, previous, deps) {
18414
+ const rolledBack = await rollbackRestart(root, previous, deps);
18415
+ return rolledBack ? failure(
18416
+ "restart_failed_rolled_back",
18417
+ `Instance ${previous.name} replacement failed; the previous configuration was restored with a fresh launch.`
18418
+ ) : failure(
18419
+ "restart_failed_degraded",
18420
+ `Instance ${previous.name} replacement and rollback both failed; its saved configuration remains recoverable for a later start.`
18421
+ );
18422
+ }
18423
+ async function restartAction(root, action, deps) {
18424
+ return withLocks(root, action.name, true, async () => {
18425
+ const required = readRequiredRecord(root, action.name);
18426
+ if (required.kind === "error") return required;
18427
+ const current = required.value;
18428
+ const live = await classifyRecord(current, deps);
18429
+ if (live.state === "conflict") {
18430
+ return failure(
18431
+ live.code,
18432
+ `Instance ${current.name} does not own its saved port pair; refusing to replace another process.`
18433
+ );
18434
+ }
18435
+ const planned = await planRestartRecord(root, current, action, live.state === "running", deps);
18436
+ if (planned.kind === "error") return planned;
18437
+ if (live.state === "running") {
18438
+ const stopped = await stopRecord(current, deps);
18439
+ if (stopped.kind === "error") return stopped;
18440
+ if (planned.value.publicPort === current.publicPort && planned.value.upstreamPort === current.upstreamPort) {
18441
+ const check = deps.isPortAvailable ?? isPortAvailableByBinding;
18442
+ if (!await check(current.publicPort, current.host) || !await check(current.upstreamPort, DEFAULT_INSTANCE_HOST)) {
18443
+ return failure(
18444
+ "port_conflict",
18445
+ `Instance ${current.name} ports did not become available after shutdown.`
18446
+ );
18447
+ }
18448
+ }
18449
+ }
18450
+ const saved = saveRecord(root, planned.value);
18451
+ if (saved.kind === "error") {
18452
+ return live.state === "running" ? restartFailureAfterStop(root, current, deps) : saved;
18453
+ }
18454
+ const launched = await launchRecord(saved.value, action.overrides.open, deps);
18455
+ if (launched.kind === "error") {
18456
+ return live.state === "running" ? restartFailureAfterStop(root, current, deps) : launched;
18457
+ }
18458
+ return success(
18459
+ operationOutput("restart", "restarted", statusOutput(saved.value, launched.value))
18460
+ );
18461
+ });
18462
+ }
18463
+ async function stopAction(root, action, deps) {
18464
+ return withLocks(root, action.name, false, async () => {
18465
+ const required = readRequiredRecord(root, action.name);
18466
+ if (required.kind === "error") return required;
18467
+ const stopped = await stopRecord(required.value, deps);
18468
+ return stopped.kind === "error" ? stopped : success(
18469
+ operationOutput(
18470
+ "stop",
18471
+ stopped.value.outcome,
18472
+ statusOutput(required.value, stopped.value.live)
18473
+ )
18474
+ );
18475
+ });
18476
+ }
18477
+ async function statusAction(root, name2, deps) {
18478
+ const required = readRequiredRecord(root, name2);
18479
+ if (required.kind === "error") return required;
18480
+ const live = await classifyRecord(required.value, deps);
18481
+ return success(statusOutput(required.value, live));
18482
+ }
18483
+ async function listAction(root, deps) {
18484
+ const records = listInstanceRecords(root);
18485
+ if (records.kind === "error") return fromRegistry(records);
18486
+ const outputs = await Promise.all(
18487
+ records.value.map(async (record2) => statusOutput(record2, await classifyRecord(record2, deps)))
18488
+ );
18489
+ return success(outputs);
18490
+ }
18491
+ function requestActionOverrides(input) {
18492
+ return {
18493
+ port: input.port ?? null,
18494
+ basePath: input.basePath === void 0 ? null : normalizeBasePath(input.basePath),
18495
+ host: input.host ?? null,
18496
+ captureMode: input.captureMode ?? null,
18497
+ dataDir: input.dataDir ?? null,
18498
+ open: false
18499
+ };
18500
+ }
18501
+ function lifecycleRoot(deps) {
18502
+ return resolve(deps.root ?? getInstancesRoot());
18503
+ }
18504
+ function normalizedServiceName(rawName) {
18505
+ const validated = validateInstanceName(rawName);
18506
+ return validated.kind === "error" ? fromRegistry(validated) : success(validated.value);
18507
+ }
18508
+ async function startNamedInstance(rawName, input = {}, deps = {}) {
18509
+ const name2 = normalizedServiceName(rawName);
18510
+ if (name2.kind === "error") return name2;
18511
+ return startAction(
18512
+ lifecycleRoot(deps),
18513
+ { kind: "start", name: name2.value, overrides: requestActionOverrides(input), json: true },
18514
+ deps
18515
+ );
18516
+ }
18517
+ async function restartNamedInstance(rawName, input = {}, deps = {}) {
18518
+ const name2 = normalizedServiceName(rawName);
18519
+ if (name2.kind === "error") return name2;
18520
+ return restartAction(
18521
+ lifecycleRoot(deps),
18522
+ { kind: "restart", name: name2.value, overrides: requestActionOverrides(input), json: true },
18523
+ deps
18524
+ );
18525
+ }
18526
+ async function stopNamedInstance(rawName, deps = {}) {
18527
+ const name2 = normalizedServiceName(rawName);
18528
+ if (name2.kind === "error") return name2;
18529
+ return stopAction(lifecycleRoot(deps), { kind: "stop", name: name2.value, json: true }, deps);
18530
+ }
18531
+ async function getNamedInstance(rawName, deps = {}) {
18532
+ const name2 = normalizedServiceName(rawName);
18533
+ if (name2.kind === "error") return name2;
18534
+ return statusAction(lifecycleRoot(deps), name2.value, deps);
18535
+ }
18536
+ async function getNamedInstanceConnection(rawName, deps = {}) {
18537
+ const instance = await getNamedInstance(rawName, deps);
18538
+ return instance.kind === "error" ? instance : success(connectionOutput(instance.value));
18539
+ }
18540
+ async function listNamedInstances(deps = {}) {
18541
+ return listAction(lifecycleRoot(deps), deps);
18542
+ }
18543
+ const NO_STORE_HEADERS$1 = { "cache-control": "no-store" };
18544
+ function errorStatus(code) {
18545
+ switch (code) {
18546
+ case "argument_invalid":
18547
+ case "data_dir_invalid":
18548
+ case "name_invalid":
18549
+ case "port_invalid":
18550
+ case "record_invalid":
18551
+ return 400;
18552
+ case "instance_not_found":
18553
+ return 404;
18554
+ case "config_mismatch":
18555
+ case "data_dir_conflict":
18556
+ case "identity_mismatch":
18557
+ case "port_conflict":
18558
+ case "self_lifecycle_unsupported":
18559
+ return 409;
18560
+ case "lock_not_owned":
18561
+ case "lock_timeout":
18562
+ return 423;
18563
+ case "launch_failed":
18564
+ case "launch_unavailable":
18565
+ case "port_exhausted":
18566
+ case "registry_io":
18567
+ case "restart_failed_degraded":
18568
+ case "restart_failed_rolled_back":
18569
+ case "shutdown_failed":
18570
+ return 503;
18571
+ }
18572
+ }
18573
+ function instanceErrorResponse(error) {
18574
+ return Response.json(instanceErrorOutput(error), {
18575
+ status: errorStatus(error.code),
18576
+ headers: NO_STORE_HEADERS$1
18577
+ });
18578
+ }
18579
+ function instanceResultResponse(result, successStatus = 200) {
18580
+ return result.kind === "error" ? instanceErrorResponse(result.error) : Response.json(result.value, { status: successStatus, headers: NO_STORE_HEADERS$1 });
18581
+ }
18582
+ async function parseInstanceBody(request, schema) {
18583
+ let value;
18584
+ try {
18585
+ const text = await request.text();
18586
+ value = text.trim().length === 0 ? {} : JSON.parse(text);
18587
+ } catch {
18588
+ return {
18589
+ ok: false,
18590
+ response: instanceErrorResponse({
18591
+ code: "argument_invalid",
18592
+ message: "Request body must be valid JSON.",
18593
+ retryable: false
18594
+ })
18595
+ };
18596
+ }
18597
+ const parsed = schema.safeParse(value);
18598
+ if (!parsed.success) {
18599
+ return {
18600
+ ok: false,
18601
+ response: instanceErrorResponse({
18602
+ code: "argument_invalid",
18603
+ message: `Invalid instance request: ${parsed.error.issues[0]?.message ?? "invalid body"}`,
18604
+ retryable: false
18605
+ })
18606
+ };
18607
+ }
18608
+ return { ok: true, value: parsed.data };
18609
+ }
18610
+ function selfLifecycleError(rawName) {
18611
+ const current = readManagedInstanceLaunch(process.env);
18612
+ return current.kind === "managed" && current.launch.name.toLowerCase() === rawName.toLowerCase() ? {
18613
+ code: "self_lifecycle_unsupported",
18614
+ message: "A managed runtime cannot stop or restart itself through its own REST/MCP transport; use the CLI or a different controller instance.",
18615
+ retryable: false
18616
+ } : null;
18617
+ }
18618
+ function instanceListResponse(instances) {
18619
+ return Response.json(
18620
+ { schemaVersion: INSTANCE_API_SCHEMA_VERSION, instances },
18621
+ { headers: NO_STORE_HEADERS$1 }
18622
+ );
18623
+ }
18624
+ const Route$H = createFileRoute("/api/instances")({
18625
+ server: {
18626
+ handlers: {
18627
+ GET: async () => {
18628
+ const result = await listNamedInstances();
18629
+ return result.kind === "error" ? instanceResultResponse(result) : instanceListResponse(result.value);
18630
+ }
18631
+ }
18632
+ }
18633
+ });
18634
+ function createShutdownCoordinator(dependencies, deadlineMs) {
18635
+ let shutdownPromise = null;
18636
+ async function shutdown(_reason = "manual") {
18637
+ if (shutdownPromise !== null) return await shutdownPromise;
18638
+ dependencies.markShuttingDown();
18639
+ dependencies.stopAdmission();
18640
+ let forced = false;
18641
+ let forceClosed = false;
18642
+ let deadline = null;
18643
+ function forceCloseOnce() {
18644
+ if (forceClosed) return;
18645
+ forceClosed = true;
18646
+ dependencies.forceClose();
18647
+ }
18648
+ async function gracefulShutdown() {
18649
+ try {
18650
+ await dependencies.drainTraffic();
18651
+ if (forced) return { forced: true, reason: "deadline" };
18652
+ await dependencies.drainFinalizers();
18653
+ if (forced) return { forced: true, reason: "deadline" };
18654
+ await dependencies.flushPersistence();
18655
+ if (forced) return { forced: true, reason: "deadline" };
18656
+ await dependencies.closeResources();
18657
+ return { forced: false, reason: "completed" };
18658
+ } catch {
18659
+ forceCloseOnce();
18660
+ return { forced: true, reason: "error" };
18661
+ }
18662
+ }
18663
+ const timedOut = new Promise((resolve2) => {
18664
+ deadline = setTimeout(
18665
+ () => {
18666
+ forced = true;
18667
+ forceCloseOnce();
18668
+ resolve2({ forced: true, reason: "deadline" });
18669
+ },
18670
+ Math.max(1, deadlineMs)
18671
+ );
18672
+ });
18673
+ shutdownPromise = Promise.race([gracefulShutdown(), timedOut]).finally(() => {
18674
+ if (deadline !== null) clearTimeout(deadline);
18675
+ });
18676
+ return await shutdownPromise;
18677
+ }
18678
+ return { shutdown };
18679
+ }
18680
+ function createShutdownSignalHandler(coordinator, onComplete) {
18681
+ let handled = false;
18682
+ return (signal) => {
18683
+ if (handled) return;
18684
+ handled = true;
18685
+ void coordinator.shutdown(signal).then(onComplete);
18686
+ };
18687
+ }
18688
+ const DEFAULT_SHUTDOWN_DEADLINE_MS = 15e3;
18689
+ function shutdownDeadlineMs() {
18690
+ const raw = process.env["AGENT_INSPECTOR_SHUTDOWN_TIMEOUT_MS"];
18691
+ if (raw === void 0 || raw === "") return DEFAULT_SHUTDOWN_DEADLINE_MS;
18692
+ const parsed = Number(raw);
18693
+ return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= 3e5 ? parsed : DEFAULT_SHUTDOWN_DEADLINE_MS;
18694
+ }
18695
+ async function drainFinalizers() {
18696
+ await flushAllRawStreamCaptures();
18697
+ await flushSessionTasks();
18698
+ await flushToolSchemaWarningAnalysis();
18699
+ }
18700
+ async function flushPersistence() {
18701
+ await flushLogBuffer();
18702
+ await flushSessionArchiveWrites();
18703
+ await flushIndex();
18704
+ await flushApplicationLog();
18705
+ }
18706
+ async function closeResources() {
18707
+ await closeLogFinalizerWorkers();
18708
+ destroyAllSessionProcesses();
18709
+ closeSqliteLogIndex();
18710
+ await flushApplicationLog();
18711
+ }
18712
+ function forceCloseResources() {
18713
+ forceCloseLogFinalizerWorkers();
18714
+ destroyAllSessionProcesses();
18715
+ closeSqliteLogIndex();
18716
+ }
18717
+ const runtimeShutdownCoordinator = createShutdownCoordinator(
18718
+ {
18719
+ markShuttingDown: () => setRuntimeShuttingDown(true),
18720
+ stopAdmission: stopRuntimeAdmission,
18721
+ drainTraffic: waitForRuntimeTrafficDrain,
16894
18722
  drainFinalizers,
16895
18723
  flushPersistence,
16896
18724
  closeResources,
@@ -16899,7 +18727,50 @@ const runtimeShutdownCoordinator = createShutdownCoordinator(
16899
18727
  shutdownDeadlineMs()
16900
18728
  );
16901
18729
  let signalHandlersInstalled = false;
18730
+ let managedInstanceHandlersInstalled = false;
18731
+ function managedControlTokensMatch(received, expected) {
18732
+ if (received.length === 0 || expected.length === 0) return false;
18733
+ const receivedDigest = createHash("sha256").update(received).digest();
18734
+ const expectedDigest = createHash("sha256").update(expected).digest();
18735
+ return timingSafeEqual(receivedDigest, expectedDigest);
18736
+ }
18737
+ function createManagedRuntimeShutdownController(options) {
18738
+ let shutdownRequested = false;
18739
+ const requestShutdown = () => {
18740
+ if (shutdownRequested) return;
18741
+ shutdownRequested = true;
18742
+ void options.shutdown().then(
18743
+ (result) => options.exit(result.forced ? 1 : 0),
18744
+ () => options.exit(1)
18745
+ );
18746
+ };
18747
+ return {
18748
+ handleDisconnect: requestShutdown,
18749
+ handleMessage: (message) => {
18750
+ const parsed = parseManagedInstanceShutdownMessage(message);
18751
+ if (parsed === null || !managedControlTokensMatch(parsed.controlToken, options.controlToken)) {
18752
+ return;
18753
+ }
18754
+ requestShutdown();
18755
+ }
18756
+ };
18757
+ }
18758
+ function installRuntimeManagedInstanceShutdownHandlers() {
18759
+ if (managedInstanceHandlersInstalled) return;
18760
+ const launchResult = readManagedInstanceLaunch(process.env);
18761
+ if (launchResult.kind !== "managed") return;
18762
+ managedInstanceHandlersInstalled = true;
18763
+ const controller = createManagedRuntimeShutdownController({
18764
+ controlToken: launchResult.launch.controlToken,
18765
+ shutdown: async () => await runtimeShutdownCoordinator.shutdown("manual"),
18766
+ exit: (code) => process.exit(code)
18767
+ });
18768
+ process.on("message", controller.handleMessage);
18769
+ process.once("disconnect", controller.handleDisconnect);
18770
+ if (process.connected === false) process.nextTick(controller.handleDisconnect);
18771
+ }
16902
18772
  function installRuntimeShutdownSignalHandlers() {
18773
+ installRuntimeManagedInstanceShutdownHandlers();
16903
18774
  if (signalHandlersInstalled) return;
16904
18775
  signalHandlersInstalled = true;
16905
18776
  const handleSignal = createShutdownSignalHandler(runtimeShutdownCoordinator, (result) => {
@@ -16910,7 +18781,7 @@ function installRuntimeShutdownSignalHandlers() {
16910
18781
  }
16911
18782
  installRuntimeShutdownSignalHandlers();
16912
18783
  logger.debug("Health endpoint loaded");
16913
- const Route$B = createFileRoute("/api/health")({
18784
+ const Route$G = createFileRoute("/api/health")({
16914
18785
  server: {
16915
18786
  handlers: {
16916
18787
  GET: async () => {
@@ -16951,7 +18822,7 @@ function readDeleteEvidenceFlag$1(request) {
16951
18822
  return { ok: false };
16952
18823
  }
16953
18824
  }
16954
- const Route$A = createFileRoute("/api/groups")({
18825
+ const Route$F = createFileRoute("/api/groups")({
16955
18826
  server: {
16956
18827
  handlers: {
16957
18828
  GET: () => Response.json(listInspectorGroups()),
@@ -16995,7 +18866,7 @@ const RuntimeConfigPatchSchema = object({
16995
18866
  }).strict().refine((v) => Object.keys(v).length > 0, {
16996
18867
  message: "At least one field must be provided"
16997
18868
  });
16998
- const Route$z = createFileRoute("/api/config")({
18869
+ const Route$E = createFileRoute("/api/config")({
16999
18870
  server: {
17000
18871
  handlers: {
17001
18872
  GET: () => {
@@ -17090,23 +18961,23 @@ function listInspectorAlerts(options) {
17090
18961
  function getInspectorAlertSummary(options) {
17091
18962
  return getAlertSummary(options);
17092
18963
  }
17093
- function parseFilters(url) {
17094
- const severityResult = AlertSeveritySchema.safeParse(url.searchParams.get("severity"));
17095
- const categoryResult = AlertCategorySchema.safeParse(url.searchParams.get("category"));
17096
- const sourceResult = AlertSourceSchema.safeParse(url.searchParams.get("source"));
18964
+ function parseFilters(url2) {
18965
+ const severityResult = AlertSeveritySchema.safeParse(url2.searchParams.get("severity"));
18966
+ const categoryResult = AlertCategorySchema.safeParse(url2.searchParams.get("category"));
18967
+ const sourceResult = AlertSourceSchema.safeParse(url2.searchParams.get("source"));
17097
18968
  return {
17098
18969
  severity: severityResult.success ? severityResult.data : void 0,
17099
18970
  category: categoryResult.success ? categoryResult.data : void 0,
17100
18971
  source: sourceResult.success ? sourceResult.data : void 0
17101
18972
  };
17102
18973
  }
17103
- const Route$y = createFileRoute("/api/alerts")({
18974
+ const Route$D = createFileRoute("/api/alerts")({
17104
18975
  server: {
17105
18976
  handlers: {
17106
18977
  GET: async ({ request }) => {
17107
- const url = new URL(request.url);
18978
+ const url2 = new URL(request.url);
17108
18979
  const limitResult = parseBoundedIntegerParameter({
17109
- value: url.searchParams.get("limit"),
18980
+ value: url2.searchParams.get("limit"),
17110
18981
  parameter: "limit",
17111
18982
  fallback: DEFAULT_ALERT_LIMIT,
17112
18983
  minimum: 1,
@@ -17115,7 +18986,7 @@ const Route$y = createFileRoute("/api/alerts")({
17115
18986
  });
17116
18987
  if (!limitResult.ok) return limitResult.response;
17117
18988
  const scanLimitResult = parseBoundedIntegerParameter({
17118
- value: url.searchParams.get("scanLimit"),
18989
+ value: url2.searchParams.get("scanLimit"),
17119
18990
  parameter: "scanLimit",
17120
18991
  fallback: DEFAULT_ALERT_SCAN_LIMIT,
17121
18992
  minimum: 1,
@@ -17125,7 +18996,7 @@ const Route$y = createFileRoute("/api/alerts")({
17125
18996
  if (!scanLimitResult.ok) return scanLimitResult.response;
17126
18997
  return Response.json(
17127
18998
  await listInspectorAlerts({
17128
- ...parseFilters(url),
18999
+ ...parseFilters(url2),
17129
19000
  limit: limitResult.value,
17130
19001
  scanLimit: scanLimitResult.value
17131
19002
  })
@@ -17143,7 +19014,7 @@ async function readJsonBody$4(request) {
17143
19014
  return { ok: false };
17144
19015
  }
17145
19016
  }
17146
- const Route$x = createFileRoute("/api/runs/$runId")({
19017
+ const Route$C = createFileRoute("/api/runs/$runId")({
17147
19018
  server: {
17148
19019
  handlers: {
17149
19020
  GET: ({ params }) => {
@@ -17228,9 +19099,9 @@ const KNOWN_PROVIDER_NAMES = {
17228
19099
  lingyiwanwu: "LingyiWanwu",
17229
19100
  stepfun: "StepFun"
17230
19101
  };
17231
- function deriveNameFromUrl(url) {
19102
+ function deriveNameFromUrl(url2) {
17232
19103
  try {
17233
- const hostname = new URL(url).hostname;
19104
+ const hostname = new URL(url2).hostname;
17234
19105
  const parts = hostname.split(".");
17235
19106
  const domain = parts.length >= 2 ? parts[parts.length - 2] ?? hostname : hostname;
17236
19107
  const domainLower = domain.toLowerCase();
@@ -17599,8 +19470,8 @@ function scanExternalProviders() {
17599
19470
  }
17600
19471
  const allProviders = [...claudeProviders, ...opencodeProviders, ...mimoProviders];
17601
19472
  const filteredProviders = allProviders.filter((p) => {
17602
- const url = p.anthropicBaseUrl || p.openaiBaseUrl || p.openaiResponsesBaseUrl;
17603
- return !/(?:localhost|127\.0\.0\.1)/.test(url);
19473
+ const url2 = p.anthropicBaseUrl || p.openaiBaseUrl || p.openaiResponsesBaseUrl;
19474
+ return !/(?:localhost|127\.0\.0\.1)/.test(url2);
17604
19475
  });
17605
19476
  let existing = [];
17606
19477
  try {
@@ -17676,7 +19547,7 @@ function consumeProviderScan(scanId, selectionIds, now = Date.now()) {
17676
19547
  }
17677
19548
  return selected;
17678
19549
  }
17679
- const Route$w = createFileRoute("/api/providers/scan")({
19550
+ const Route$B = createFileRoute("/api/providers/scan")({
17680
19551
  server: {
17681
19552
  handlers: {
17682
19553
  POST: () => {
@@ -17722,7 +19593,7 @@ const ProviderScanImportRequestSchema = object({
17722
19593
  selectionIds: array(string().uuid()).min(1).max(100)
17723
19594
  });
17724
19595
  const ProviderFileImportSchema = union([string(), object({ providers: unknown() })]);
17725
- const Route$v = createFileRoute("/api/providers/import")({
19596
+ const Route$A = createFileRoute("/api/providers/import")({
17726
19597
  server: {
17727
19598
  handlers: {
17728
19599
  POST: async ({ request }) => {
@@ -17794,7 +19665,7 @@ function exportResponse(json, filename) {
17794
19665
  }
17795
19666
  });
17796
19667
  }
17797
- const Route$u = createFileRoute("/api/providers/export")({
19668
+ const Route$z = createFileRoute("/api/providers/export")({
17798
19669
  server: {
17799
19670
  handlers: {
17800
19671
  GET: () => {
@@ -17837,7 +19708,7 @@ const ProviderUpdateSchema = object({
17837
19708
  modelMetadata: ProviderModelMetadataListSchema.optional(),
17838
19709
  source: _enum(["company", "personal"]).optional()
17839
19710
  });
17840
- const Route$t = createFileRoute("/api/providers/$providerId")({
19711
+ const Route$y = createFileRoute("/api/providers/$providerId")({
17841
19712
  server: {
17842
19713
  handlers: {
17843
19714
  GET: ({ params }) => {
@@ -17905,8 +19776,8 @@ const Route$t = createFileRoute("/api/providers/$providerId")({
17905
19776
  const INITIAL_STREAM_LOG_LIMIT = 100;
17906
19777
  const UPDATE_COALESCE_MS = 50;
17907
19778
  const sseClientLimiter = createCapacityLimiter(MAX_SSE_CLIENTS);
17908
- function streamIncludesBodies(url) {
17909
- return url.searchParams.get("compact") === "0";
19779
+ function streamIncludesBodies(url2) {
19780
+ return url2.searchParams.get("compact") === "0";
17910
19781
  }
17911
19782
  function parseLastEventLogId(value) {
17912
19783
  if (value === null || !/^\d+$/.test(value)) return void 0;
@@ -17933,10 +19804,10 @@ function createLogsStreamResponse(request, clientLimiter = sseClientLimiter) {
17933
19804
  retryAfterSeconds: 1
17934
19805
  });
17935
19806
  }
17936
- const url = new URL(request.url);
17937
- const sessionId = url.searchParams.get("sessionId") ?? void 0;
17938
- const model = url.searchParams.get("model") ?? void 0;
17939
- const includeBodies = streamIncludesBodies(url);
19807
+ const url2 = new URL(request.url);
19808
+ const sessionId = url2.searchParams.get("sessionId") ?? void 0;
19809
+ const model = url2.searchParams.get("model") ?? void 0;
19810
+ const includeBodies = streamIncludesBodies(url2);
17940
19811
  const lastEventLogId = parseLastEventLogId(request.headers.get("last-event-id"));
17941
19812
  let controllerRef = null;
17942
19813
  let cleanedUp = false;
@@ -18024,7 +19895,7 @@ function createLogsStreamResponse(request, clientLimiter = sseClientLimiter) {
18024
19895
  }
18025
19896
  });
18026
19897
  }
18027
- const Route$s = createFileRoute("/api/logs/stream")({
19898
+ const Route$x = createFileRoute("/api/logs/stream")({
18028
19899
  server: {
18029
19900
  handlers: {
18030
19901
  GET: ({ request }) => createLogsStreamResponse(request)
@@ -18714,7 +20585,7 @@ async function readBoundedLogImportUpload(request, options = {}) {
18714
20585
  data: new Uint8Array(await upload.arrayBuffer())
18715
20586
  };
18716
20587
  }
18717
- const Route$r = createFileRoute("/api/logs/import")({
20588
+ const Route$w = createFileRoute("/api/logs/import")({
18718
20589
  server: {
18719
20590
  handlers: {
18720
20591
  POST: async ({ request }) => {
@@ -18745,7 +20616,7 @@ const Route$r = createFileRoute("/api/logs/import")({
18745
20616
  }
18746
20617
  }
18747
20618
  });
18748
- const Route$q = createFileRoute("/api/logs/$id")({
20619
+ const Route$v = createFileRoute("/api/logs/$id")({
18749
20620
  server: {
18750
20621
  handlers: {
18751
20622
  GET: async ({ params }) => {
@@ -19128,20 +20999,20 @@ const OpenClawWriteResponseSchema = object({
19128
20999
  memoryId: string().optional()
19129
21000
  });
19130
21001
  function getLegacyEndpoint() {
19131
- const endpoint = process.env["OPENCLAW_MEMORY_URL"] ?? process.env["OPENCLAW_API_URL"];
19132
- if (endpoint === void 0 || endpoint.trim() === "") return null;
19133
- return endpoint.trim();
21002
+ const endpoint2 = process.env["OPENCLAW_MEMORY_URL"] ?? process.env["OPENCLAW_API_URL"];
21003
+ if (endpoint2 === void 0 || endpoint2.trim() === "") return null;
21004
+ return endpoint2.trim();
19134
21005
  }
19135
- function buildMemoryUrl(endpoint) {
19136
- return endpoint.endsWith("/memories") ? endpoint : `${endpoint.replace(/\/$/, "")}/memories`;
21006
+ function buildMemoryUrl(endpoint2) {
21007
+ return endpoint2.endsWith("/memories") ? endpoint2 : `${endpoint2.replace(/\/$/, "")}/memories`;
19137
21008
  }
19138
- function buildSearchUrl(endpoint, query, project) {
19139
- const url = new URL(`${endpoint.replace(/\/$/, "")}/search`);
19140
- url.searchParams.set("q", query);
21009
+ function buildSearchUrl(endpoint2, query, project) {
21010
+ const url2 = new URL(`${endpoint2.replace(/\/$/, "")}/search`);
21011
+ url2.searchParams.set("q", query);
19141
21012
  if (project !== void 0 && project !== "") {
19142
- url.searchParams.set("project", project);
21013
+ url2.searchParams.set("project", project);
19143
21014
  }
19144
- return url.toString();
21015
+ return url2.toString();
19145
21016
  }
19146
21017
  function authHeaders() {
19147
21018
  const headers = new Headers({ "content-type": "application/json" });
@@ -19172,15 +21043,15 @@ async function promoteToOpenClaw(candidate) {
19172
21043
  }
19173
21044
  return { success: false, error: result.error };
19174
21045
  }
19175
- const endpoint = getLegacyEndpoint();
19176
- if (endpoint === null) {
21046
+ const endpoint2 = getLegacyEndpoint();
21047
+ if (endpoint2 === null) {
19177
21048
  return {
19178
21049
  success: false,
19179
21050
  error: "OpenClaw memory backend is not configured. Set OPENCLAW_WORKSPACE_DIR for file-backed memory or OPENCLAW_MEMORY_URL for a legacy HTTP backend."
19180
21051
  };
19181
21052
  }
19182
21053
  const fetchResult = await safeFetch(
19183
- buildMemoryUrl(endpoint),
21054
+ buildMemoryUrl(endpoint2),
19184
21055
  {
19185
21056
  method: "POST",
19186
21057
  headers: authHeaders(),
@@ -19204,8 +21075,8 @@ async function searchOpenClaw(query, project) {
19204
21075
  if (isOpenClawGatewayConfigured()) {
19205
21076
  return await searchOpenClawGateway(query, project);
19206
21077
  }
19207
- const endpoint = getLegacyEndpoint();
19208
- if (endpoint === null) {
21078
+ const endpoint2 = getLegacyEndpoint();
21079
+ if (endpoint2 === null) {
19209
21080
  const workspaceHint = isOpenClawFileBridgeConfigured() ? " OPENCLAW_WORKSPACE_DIR is configured for writes, but search requires OPENCLAW_GATEWAY_URL." : "";
19210
21081
  return {
19211
21082
  results: [],
@@ -19213,7 +21084,7 @@ async function searchOpenClaw(query, project) {
19213
21084
  };
19214
21085
  }
19215
21086
  const fetchResult = await safeFetch(
19216
- buildSearchUrl(endpoint, query, project),
21087
+ buildSearchUrl(endpoint2, query, project),
19217
21088
  {
19218
21089
  method: "GET",
19219
21090
  headers: authHeaders()
@@ -19255,13 +21126,13 @@ function bodySearchQuery(value) {
19255
21126
  const query = descriptor.value;
19256
21127
  return typeof query === "string" ? query : null;
19257
21128
  }
19258
- const Route$p = createFileRoute("/api/knowledge/search")({
21129
+ const Route$u = createFileRoute("/api/knowledge/search")({
19259
21130
  server: {
19260
21131
  handlers: {
19261
21132
  GET: async ({ request }) => {
19262
- const url = new URL(request.url);
19263
- const query = url.searchParams.get("q") ?? "";
19264
- const project = url.searchParams.get("project") ?? void 0;
21133
+ const url2 = new URL(request.url);
21134
+ const query = url2.searchParams.get("q") ?? "";
21135
+ const project = url2.searchParams.get("project") ?? void 0;
19265
21136
  if (query === "") {
19266
21137
  return Response.json({ error: "Missing q search parameter" }, { status: 400 });
19267
21138
  }
@@ -19288,12 +21159,12 @@ const Route$p = createFileRoute("/api/knowledge/search")({
19288
21159
  }
19289
21160
  }
19290
21161
  });
19291
- const Route$o = createFileRoute("/api/knowledge/project-context")({
21162
+ const Route$t = createFileRoute("/api/knowledge/project-context")({
19292
21163
  server: {
19293
21164
  handlers: {
19294
21165
  GET: async ({ request }) => {
19295
- const url = new URL(request.url);
19296
- const project = url.searchParams.get("project") ?? "";
21166
+ const url2 = new URL(request.url);
21167
+ const project = url2.searchParams.get("project") ?? "";
19297
21168
  if (project === "") {
19298
21169
  return Response.json({ error: "Missing project search parameter" }, { status: 400 });
19299
21170
  }
@@ -19313,13 +21184,20 @@ const Route$o = createFileRoute("/api/knowledge/project-context")({
19313
21184
  }
19314
21185
  }
19315
21186
  });
19316
- const Route$n = createFileRoute("/api/knowledge/candidates")({
21187
+ const Route$s = createFileRoute("/api/knowledge/candidates")({
19317
21188
  server: {
19318
21189
  handlers: {
19319
21190
  GET: () => Response.json({ candidates: listCandidates() })
19320
21191
  }
19321
21192
  }
19322
21193
  });
21194
+ const Route$r = createFileRoute("/api/instances/$name")({
21195
+ server: {
21196
+ handlers: {
21197
+ GET: async ({ params }) => instanceResultResponse(await getNamedInstance(params.name))
21198
+ }
21199
+ }
21200
+ });
19323
21201
  async function readJsonBody$3(request) {
19324
21202
  try {
19325
21203
  const raw = await request.text();
@@ -19348,7 +21226,7 @@ function readDeleteEvidenceFlag(request) {
19348
21226
  return { ok: false };
19349
21227
  }
19350
21228
  }
19351
- const Route$m = createFileRoute("/api/groups/$groupId")({
21229
+ const Route$q = createFileRoute("/api/groups/$groupId")({
19352
21230
  server: {
19353
21231
  handlers: {
19354
21232
  GET: ({ params }) => {
@@ -19395,16 +21273,6 @@ const Route$m = createFileRoute("/api/groups/$groupId")({
19395
21273
  }
19396
21274
  }
19397
21275
  });
19398
- function platformCommand(command, args, platform = process.platform) {
19399
- if (platform !== "win32") return { command, args: [...args] };
19400
- return { command: "cmd.exe", args: ["/d", "/s", "/c", command, ...args] };
19401
- }
19402
- function npmCommand(platform = process.platform) {
19403
- return platform === "win32" ? "npm.cmd" : "npm";
19404
- }
19405
- function npmSpawnCommand(args, platform = process.platform) {
19406
- return platformCommand(npmCommand(platform), args, platform);
19407
- }
19408
21276
  const ECOSYSTEM_PACKAGES = [
19409
21277
  {
19410
21278
  id: "inspector",
@@ -19886,7 +21754,7 @@ ${error.message}
19886
21754
  });
19887
21755
  return task;
19888
21756
  }
19889
- const Route$l = createFileRoute("/api/ecosystem/tasks")({
21757
+ const Route$p = createFileRoute("/api/ecosystem/tasks")({
19890
21758
  server: {
19891
21759
  handlers: {
19892
21760
  GET: () => {
@@ -19895,7 +21763,7 @@ const Route$l = createFileRoute("/api/ecosystem/tasks")({
19895
21763
  }
19896
21764
  }
19897
21765
  });
19898
- const Route$k = createFileRoute("/api/ecosystem/packages")({
21766
+ const Route$o = createFileRoute("/api/ecosystem/packages")({
19899
21767
  server: {
19900
21768
  handlers: {
19901
21769
  GET: async () => {
@@ -19909,7 +21777,7 @@ const Route$k = createFileRoute("/api/ecosystem/packages")({
19909
21777
  }
19910
21778
  }
19911
21779
  });
19912
- const Route$j = createFileRoute("/api/config/paths")({
21780
+ const Route$n = createFileRoute("/api/config/paths")({
19913
21781
  server: {
19914
21782
  handlers: {
19915
21783
  GET: () => {
@@ -19920,13 +21788,13 @@ const Route$j = createFileRoute("/api/config/paths")({
19920
21788
  }
19921
21789
  }
19922
21790
  });
19923
- const Route$i = createFileRoute("/api/alerts/summary")({
21791
+ const Route$m = createFileRoute("/api/alerts/summary")({
19924
21792
  server: {
19925
21793
  handlers: {
19926
21794
  GET: async ({ request }) => {
19927
- const url = new URL(request.url);
21795
+ const url2 = new URL(request.url);
19928
21796
  const scanLimitResult = parseBoundedIntegerParameter({
19929
- value: url.searchParams.get("scanLimit"),
21797
+ value: url2.searchParams.get("scanLimit"),
19930
21798
  parameter: "scanLimit",
19931
21799
  fallback: DEFAULT_ALERT_SCAN_LIMIT,
19932
21800
  minimum: 1,
@@ -19952,7 +21820,7 @@ async function readJsonBody$2(request) {
19952
21820
  return { ok: false };
19953
21821
  }
19954
21822
  }
19955
- const Route$h = createFileRoute("/api/runs/$runId/evidence")({
21823
+ const Route$l = createFileRoute("/api/runs/$runId/evidence")({
19956
21824
  server: {
19957
21825
  handlers: {
19958
21826
  GET: ({ params }) => {
@@ -20699,7 +22567,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, protocol)
20699
22567
  clearTimeout(timeoutId);
20700
22568
  }
20701
22569
  }
20702
- const Route$g = createFileRoute("/api/providers/$providerId/test")({
22570
+ const Route$k = createFileRoute("/api/providers/$providerId/test")({
20703
22571
  server: {
20704
22572
  handlers: {
20705
22573
  POST: async ({ params }) => {
@@ -20882,7 +22750,7 @@ async function readRegistryJson(response) {
20882
22750
  return null;
20883
22751
  }
20884
22752
  }
20885
- const Route$f = createFileRoute("/api/providers/$providerId/model-metadata")({
22753
+ const Route$j = createFileRoute("/api/providers/$providerId/model-metadata")({
20886
22754
  server: {
20887
22755
  handlers: {
20888
22756
  POST: async ({ params, request }) => {
@@ -20997,7 +22865,7 @@ const Route$f = createFileRoute("/api/providers/$providerId/model-metadata")({
20997
22865
  const ReplayRequestSchema = object({
20998
22866
  modifiedBody: string()
20999
22867
  });
21000
- const Route$e = createFileRoute("/api/logs/$id/replay")({
22868
+ const Route$i = createFileRoute("/api/logs/$id/replay")({
21001
22869
  server: {
21002
22870
  handlers: {
21003
22871
  POST: async ({ params, request }) => {
@@ -21209,7 +23077,7 @@ const Route$e = createFileRoute("/api/logs/$id/replay")({
21209
23077
  }
21210
23078
  }
21211
23079
  });
21212
- const Route$d = createFileRoute("/api/logs/$id/chunks")({
23080
+ const Route$h = createFileRoute("/api/logs/$id/chunks")({
21213
23081
  server: {
21214
23082
  handlers: {
21215
23083
  GET: async ({ params }) => {
@@ -21316,7 +23184,7 @@ function parseIntegerParam(value, fallback) {
21316
23184
  if (!Number.isInteger(parsed)) return fallback;
21317
23185
  return parsed;
21318
23186
  }
21319
- const Route$c = createFileRoute("/api/logs/$id/body")({
23187
+ const Route$g = createFileRoute("/api/logs/$id/body")({
21320
23188
  server: {
21321
23189
  handlers: {
21322
23190
  GET: async ({ params, request }) => {
@@ -21324,13 +23192,13 @@ const Route$c = createFileRoute("/api/logs/$id/body")({
21324
23192
  if (!Number.isInteger(id) || id <= 0) {
21325
23193
  return Response.json({ error: "Invalid log ID" }, { status: 400 });
21326
23194
  }
21327
- const url = new URL(request.url);
21328
- const partResult = LogBodyPartSchema.safeParse(url.searchParams.get("part"));
23195
+ const url2 = new URL(request.url);
23196
+ const partResult = LogBodyPartSchema.safeParse(url2.searchParams.get("part"));
21329
23197
  if (!partResult.success) {
21330
23198
  return Response.json({ error: "Invalid body part" }, { status: 400 });
21331
23199
  }
21332
23200
  const limitResult = parseBoundedIntegerParameter({
21333
- value: url.searchParams.get("limit"),
23201
+ value: url2.searchParams.get("limit"),
21334
23202
  parameter: "limit",
21335
23203
  fallback: DEFAULT_LOG_BODY_CHUNK_BYTES,
21336
23204
  minimum: 1,
@@ -21346,7 +23214,7 @@ const Route$c = createFileRoute("/api/logs/$id/body")({
21346
23214
  createLogBodyChunk({
21347
23215
  log,
21348
23216
  part: partResult.data,
21349
- offset: parseIntegerParam(url.searchParams.get("offset"), 0),
23217
+ offset: parseIntegerParam(url2.searchParams.get("offset"), 0),
21350
23218
  limit: limitResult.value
21351
23219
  })
21352
23220
  );
@@ -21363,7 +23231,7 @@ const CandidateUpdateSchema = object({
21363
23231
  object({
21364
23232
  candidate: KnowledgeCandidateSchema
21365
23233
  });
21366
- const Route$b = createFileRoute("/api/knowledge/candidates/$candidateId")({
23234
+ const Route$f = createFileRoute("/api/knowledge/candidates/$candidateId")({
21367
23235
  server: {
21368
23236
  handlers: {
21369
23237
  PATCH: async ({ params, request }) => {
@@ -21391,6 +23259,52 @@ const Route$b = createFileRoute("/api/knowledge/candidates/$candidateId")({
21391
23259
  }
21392
23260
  }
21393
23261
  });
23262
+ const Route$e = createFileRoute("/api/instances/$name/stop")({
23263
+ server: {
23264
+ handlers: {
23265
+ POST: async ({ params, request }) => {
23266
+ const body = await parseInstanceBody(request, InstanceEmptyRequestSchema);
23267
+ if (!body.ok) return body.response;
23268
+ const selfError = selfLifecycleError(params.name);
23269
+ if (selfError !== null) return instanceErrorResponse(selfError);
23270
+ return instanceResultResponse(await stopNamedInstance(params.name));
23271
+ }
23272
+ }
23273
+ }
23274
+ });
23275
+ const Route$d = createFileRoute("/api/instances/$name/start")({
23276
+ server: {
23277
+ handlers: {
23278
+ POST: async ({ params, request }) => {
23279
+ const body = await parseInstanceBody(request, InstanceStartRequestSchema);
23280
+ if (!body.ok) return body.response;
23281
+ const result = await startNamedInstance(params.name, body.value);
23282
+ const status = result.kind === "success" && result.value.outcome === "created" ? 201 : 200;
23283
+ return instanceResultResponse(result, status);
23284
+ }
23285
+ }
23286
+ }
23287
+ });
23288
+ const Route$c = createFileRoute("/api/instances/$name/restart")({
23289
+ server: {
23290
+ handlers: {
23291
+ POST: async ({ params, request }) => {
23292
+ const body = await parseInstanceBody(request, InstanceStartRequestSchema);
23293
+ if (!body.ok) return body.response;
23294
+ const selfError = selfLifecycleError(params.name);
23295
+ if (selfError !== null) return instanceErrorResponse(selfError);
23296
+ return instanceResultResponse(await restartNamedInstance(params.name, body.value));
23297
+ }
23298
+ }
23299
+ }
23300
+ });
23301
+ const Route$b = createFileRoute("/api/instances/$name/connection")({
23302
+ server: {
23303
+ handlers: {
23304
+ GET: async ({ params }) => instanceResultResponse(await getNamedInstanceConnection(params.name))
23305
+ }
23306
+ }
23307
+ });
21394
23308
  async function readJsonBody$1(request) {
21395
23309
  try {
21396
23310
  const raw = await request.text();
@@ -22271,201 +24185,231 @@ const Route = createFileRoute("/api/ecosystem/packages/$packageId/help")({
22271
24185
  }
22272
24186
  }
22273
24187
  });
22274
- const ReadyzRoute = Route$N.update({
24188
+ const ReadyzRoute = Route$T.update({
22275
24189
  id: "/readyz",
22276
24190
  path: "/readyz",
22277
- getParentRoute: () => Route$O
24191
+ getParentRoute: () => Route$U
22278
24192
  });
22279
- const LivezRoute = Route$M.update({
24193
+ const LivezRoute = Route$S.update({
22280
24194
  id: "/livez",
22281
24195
  path: "/livez",
22282
- getParentRoute: () => Route$O
24196
+ getParentRoute: () => Route$U
22283
24197
  });
22284
- const IndexRoute = Route$L.update({
24198
+ const IndexRoute = Route$R.update({
22285
24199
  id: "/",
22286
24200
  path: "/",
22287
- getParentRoute: () => Route$O
24201
+ getParentRoute: () => Route$U
22288
24202
  });
22289
- const SessionSessionIdRoute = Route$K.update({
24203
+ const SessionSessionIdRoute = Route$Q.update({
22290
24204
  id: "/session/$sessionId",
22291
24205
  path: "/session/$sessionId",
22292
- getParentRoute: () => Route$O
24206
+ getParentRoute: () => Route$U
22293
24207
  });
22294
- const ProxySplatRoute = Route$J.update({
24208
+ const ProxySplatRoute = Route$P.update({
22295
24209
  id: "/proxy/$",
22296
24210
  path: "/proxy/$",
22297
- getParentRoute: () => Route$O
24211
+ getParentRoute: () => Route$U
22298
24212
  });
22299
- const ApiSessionsRoute = Route$I.update({
24213
+ const ApiSessionsRoute = Route$O.update({
22300
24214
  id: "/api/sessions",
22301
24215
  path: "/api/sessions",
22302
- getParentRoute: () => Route$O
24216
+ getParentRoute: () => Route$U
22303
24217
  });
22304
- const ApiRunsRoute = Route$H.update({
24218
+ const ApiRunsRoute = Route$N.update({
22305
24219
  id: "/api/runs",
22306
24220
  path: "/api/runs",
22307
- getParentRoute: () => Route$O
24221
+ getParentRoute: () => Route$U
22308
24222
  });
22309
- const ApiProvidersRoute = Route$G.update({
24223
+ const ApiProvidersRoute = Route$M.update({
22310
24224
  id: "/api/providers",
22311
24225
  path: "/api/providers",
22312
- getParentRoute: () => Route$O
24226
+ getParentRoute: () => Route$U
22313
24227
  });
22314
- const ApiPiAgentRoute = Route$F.update({
24228
+ const ApiPiAgentRoute = Route$L.update({
22315
24229
  id: "/api/pi-agent",
22316
24230
  path: "/api/pi-agent",
22317
- getParentRoute: () => Route$O
24231
+ getParentRoute: () => Route$U
22318
24232
  });
22319
- const ApiModelsRoute = Route$E.update({
24233
+ const ApiModelsRoute = Route$K.update({
22320
24234
  id: "/api/models",
22321
24235
  path: "/api/models",
22322
- getParentRoute: () => Route$O
24236
+ getParentRoute: () => Route$U
22323
24237
  });
22324
- const ApiMcpRoute = Route$D.update({
24238
+ const ApiMcpRoute = Route$J.update({
22325
24239
  id: "/api/mcp",
22326
24240
  path: "/api/mcp",
22327
- getParentRoute: () => Route$O
24241
+ getParentRoute: () => Route$U
22328
24242
  });
22329
- const ApiLogsRoute = Route$C.update({
24243
+ const ApiLogsRoute = Route$I.update({
22330
24244
  id: "/api/logs",
22331
24245
  path: "/api/logs",
22332
- getParentRoute: () => Route$O
24246
+ getParentRoute: () => Route$U
24247
+ });
24248
+ const ApiInstancesRoute = Route$H.update({
24249
+ id: "/api/instances",
24250
+ path: "/api/instances",
24251
+ getParentRoute: () => Route$U
22333
24252
  });
22334
- const ApiHealthRoute = Route$B.update({
24253
+ const ApiHealthRoute = Route$G.update({
22335
24254
  id: "/api/health",
22336
24255
  path: "/api/health",
22337
- getParentRoute: () => Route$O
24256
+ getParentRoute: () => Route$U
22338
24257
  });
22339
- const ApiGroupsRoute = Route$A.update({
24258
+ const ApiGroupsRoute = Route$F.update({
22340
24259
  id: "/api/groups",
22341
24260
  path: "/api/groups",
22342
- getParentRoute: () => Route$O
24261
+ getParentRoute: () => Route$U
22343
24262
  });
22344
- const ApiConfigRoute = Route$z.update({
24263
+ const ApiConfigRoute = Route$E.update({
22345
24264
  id: "/api/config",
22346
24265
  path: "/api/config",
22347
- getParentRoute: () => Route$O
24266
+ getParentRoute: () => Route$U
22348
24267
  });
22349
- const ApiAlertsRoute = Route$y.update({
24268
+ const ApiAlertsRoute = Route$D.update({
22350
24269
  id: "/api/alerts",
22351
24270
  path: "/api/alerts",
22352
- getParentRoute: () => Route$O
24271
+ getParentRoute: () => Route$U
22353
24272
  });
22354
- const ApiRunsRunIdRoute = Route$x.update({
24273
+ const ApiRunsRunIdRoute = Route$C.update({
22355
24274
  id: "/$runId",
22356
24275
  path: "/$runId",
22357
24276
  getParentRoute: () => ApiRunsRoute
22358
24277
  });
22359
- const ApiProvidersScanRoute = Route$w.update({
24278
+ const ApiProvidersScanRoute = Route$B.update({
22360
24279
  id: "/scan",
22361
24280
  path: "/scan",
22362
24281
  getParentRoute: () => ApiProvidersRoute
22363
24282
  });
22364
- const ApiProvidersImportRoute = Route$v.update({
24283
+ const ApiProvidersImportRoute = Route$A.update({
22365
24284
  id: "/import",
22366
24285
  path: "/import",
22367
24286
  getParentRoute: () => ApiProvidersRoute
22368
24287
  });
22369
- const ApiProvidersExportRoute = Route$u.update({
24288
+ const ApiProvidersExportRoute = Route$z.update({
22370
24289
  id: "/export",
22371
24290
  path: "/export",
22372
24291
  getParentRoute: () => ApiProvidersRoute
22373
24292
  });
22374
- const ApiProvidersProviderIdRoute = Route$t.update({
24293
+ const ApiProvidersProviderIdRoute = Route$y.update({
22375
24294
  id: "/$providerId",
22376
24295
  path: "/$providerId",
22377
24296
  getParentRoute: () => ApiProvidersRoute
22378
24297
  });
22379
- const ApiLogsStreamRoute = Route$s.update({
24298
+ const ApiLogsStreamRoute = Route$x.update({
22380
24299
  id: "/stream",
22381
24300
  path: "/stream",
22382
24301
  getParentRoute: () => ApiLogsRoute
22383
24302
  });
22384
- const ApiLogsImportRoute = Route$r.update({
24303
+ const ApiLogsImportRoute = Route$w.update({
22385
24304
  id: "/import",
22386
24305
  path: "/import",
22387
24306
  getParentRoute: () => ApiLogsRoute
22388
24307
  });
22389
- const ApiLogsIdRoute = Route$q.update({
24308
+ const ApiLogsIdRoute = Route$v.update({
22390
24309
  id: "/$id",
22391
24310
  path: "/$id",
22392
24311
  getParentRoute: () => ApiLogsRoute
22393
24312
  });
22394
- const ApiKnowledgeSearchRoute = Route$p.update({
24313
+ const ApiKnowledgeSearchRoute = Route$u.update({
22395
24314
  id: "/api/knowledge/search",
22396
24315
  path: "/api/knowledge/search",
22397
- getParentRoute: () => Route$O
24316
+ getParentRoute: () => Route$U
22398
24317
  });
22399
- const ApiKnowledgeProjectContextRoute = Route$o.update({
24318
+ const ApiKnowledgeProjectContextRoute = Route$t.update({
22400
24319
  id: "/api/knowledge/project-context",
22401
24320
  path: "/api/knowledge/project-context",
22402
- getParentRoute: () => Route$O
24321
+ getParentRoute: () => Route$U
22403
24322
  });
22404
- const ApiKnowledgeCandidatesRoute = Route$n.update({
24323
+ const ApiKnowledgeCandidatesRoute = Route$s.update({
22405
24324
  id: "/api/knowledge/candidates",
22406
24325
  path: "/api/knowledge/candidates",
22407
- getParentRoute: () => Route$O
24326
+ getParentRoute: () => Route$U
22408
24327
  });
22409
- const ApiGroupsGroupIdRoute = Route$m.update({
24328
+ const ApiInstancesNameRoute = Route$r.update({
24329
+ id: "/$name",
24330
+ path: "/$name",
24331
+ getParentRoute: () => ApiInstancesRoute
24332
+ });
24333
+ const ApiGroupsGroupIdRoute = Route$q.update({
22410
24334
  id: "/$groupId",
22411
24335
  path: "/$groupId",
22412
24336
  getParentRoute: () => ApiGroupsRoute
22413
24337
  });
22414
- const ApiEcosystemTasksRoute = Route$l.update({
24338
+ const ApiEcosystemTasksRoute = Route$p.update({
22415
24339
  id: "/api/ecosystem/tasks",
22416
24340
  path: "/api/ecosystem/tasks",
22417
- getParentRoute: () => Route$O
24341
+ getParentRoute: () => Route$U
22418
24342
  });
22419
- const ApiEcosystemPackagesRoute = Route$k.update({
24343
+ const ApiEcosystemPackagesRoute = Route$o.update({
22420
24344
  id: "/api/ecosystem/packages",
22421
24345
  path: "/api/ecosystem/packages",
22422
- getParentRoute: () => Route$O
24346
+ getParentRoute: () => Route$U
22423
24347
  });
22424
- const ApiConfigPathsRoute = Route$j.update({
24348
+ const ApiConfigPathsRoute = Route$n.update({
22425
24349
  id: "/paths",
22426
24350
  path: "/paths",
22427
24351
  getParentRoute: () => ApiConfigRoute
22428
24352
  });
22429
- const ApiAlertsSummaryRoute = Route$i.update({
24353
+ const ApiAlertsSummaryRoute = Route$m.update({
22430
24354
  id: "/summary",
22431
24355
  path: "/summary",
22432
24356
  getParentRoute: () => ApiAlertsRoute
22433
24357
  });
22434
- const ApiRunsRunIdEvidenceRoute = Route$h.update({
24358
+ const ApiRunsRunIdEvidenceRoute = Route$l.update({
22435
24359
  id: "/evidence",
22436
24360
  path: "/evidence",
22437
24361
  getParentRoute: () => ApiRunsRunIdRoute
22438
24362
  });
22439
- const ApiProvidersProviderIdTestRoute = Route$g.update({
24363
+ const ApiProvidersProviderIdTestRoute = Route$k.update({
22440
24364
  id: "/test",
22441
24365
  path: "/test",
22442
24366
  getParentRoute: () => ApiProvidersProviderIdRoute
22443
24367
  });
22444
- const ApiProvidersProviderIdModelMetadataRoute = Route$f.update({
24368
+ const ApiProvidersProviderIdModelMetadataRoute = Route$j.update({
22445
24369
  id: "/model-metadata",
22446
24370
  path: "/model-metadata",
22447
24371
  getParentRoute: () => ApiProvidersProviderIdRoute
22448
24372
  });
22449
- const ApiLogsIdReplayRoute = Route$e.update({
24373
+ const ApiLogsIdReplayRoute = Route$i.update({
22450
24374
  id: "/replay",
22451
24375
  path: "/replay",
22452
24376
  getParentRoute: () => ApiLogsIdRoute
22453
24377
  });
22454
- const ApiLogsIdChunksRoute = Route$d.update({
24378
+ const ApiLogsIdChunksRoute = Route$h.update({
22455
24379
  id: "/chunks",
22456
24380
  path: "/chunks",
22457
24381
  getParentRoute: () => ApiLogsIdRoute
22458
24382
  });
22459
- const ApiLogsIdBodyRoute = Route$c.update({
24383
+ const ApiLogsIdBodyRoute = Route$g.update({
22460
24384
  id: "/body",
22461
24385
  path: "/body",
22462
24386
  getParentRoute: () => ApiLogsIdRoute
22463
24387
  });
22464
- const ApiKnowledgeCandidatesCandidateIdRoute = Route$b.update({
24388
+ const ApiKnowledgeCandidatesCandidateIdRoute = Route$f.update({
22465
24389
  id: "/$candidateId",
22466
24390
  path: "/$candidateId",
22467
24391
  getParentRoute: () => ApiKnowledgeCandidatesRoute
22468
24392
  });
24393
+ const ApiInstancesNameStopRoute = Route$e.update({
24394
+ id: "/stop",
24395
+ path: "/stop",
24396
+ getParentRoute: () => ApiInstancesNameRoute
24397
+ });
24398
+ const ApiInstancesNameStartRoute = Route$d.update({
24399
+ id: "/start",
24400
+ path: "/start",
24401
+ getParentRoute: () => ApiInstancesNameRoute
24402
+ });
24403
+ const ApiInstancesNameRestartRoute = Route$c.update({
24404
+ id: "/restart",
24405
+ path: "/restart",
24406
+ getParentRoute: () => ApiInstancesNameRoute
24407
+ });
24408
+ const ApiInstancesNameConnectionRoute = Route$b.update({
24409
+ id: "/connection",
24410
+ path: "/connection",
24411
+ getParentRoute: () => ApiInstancesNameRoute
24412
+ });
22469
24413
  const ApiGroupsGroupIdSessionsRoute = Route$a.update({
22470
24414
  id: "/sessions",
22471
24415
  path: "/sessions",
@@ -22489,7 +24433,7 @@ const ApiProvidersProviderIdTestLogRoute = Route$7.update({
22489
24433
  const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$6.update({
22490
24434
  id: "/api/knowledge/sessions/$sessionId/candidates",
22491
24435
  path: "/api/knowledge/sessions/$sessionId/candidates",
22492
- getParentRoute: () => Route$O
24436
+ getParentRoute: () => Route$U
22493
24437
  });
22494
24438
  const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route$5.update({
22495
24439
  id: "/promote",
@@ -22499,7 +24443,7 @@ const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route$5.update({
22499
24443
  const ApiEcosystemRecipesRecipeIdRunRoute = Route$4.update({
22500
24444
  id: "/api/ecosystem/recipes/$recipeId/run",
22501
24445
  path: "/api/ecosystem/recipes/$recipeId/run",
22502
- getParentRoute: () => Route$O
24446
+ getParentRoute: () => Route$U
22503
24447
  });
22504
24448
  const ApiEcosystemPackagesPackageIdUpgradeRoute = Route$3.update({
22505
24449
  id: "/$packageId/upgrade",
@@ -22544,6 +24488,19 @@ const ApiGroupsRouteChildren = {
22544
24488
  const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
22545
24489
  ApiGroupsRouteChildren
22546
24490
  );
24491
+ const ApiInstancesNameRouteChildren = {
24492
+ ApiInstancesNameConnectionRoute,
24493
+ ApiInstancesNameRestartRoute,
24494
+ ApiInstancesNameStartRoute,
24495
+ ApiInstancesNameStopRoute
24496
+ };
24497
+ const ApiInstancesNameRouteWithChildren = ApiInstancesNameRoute._addFileChildren(ApiInstancesNameRouteChildren);
24498
+ const ApiInstancesRouteChildren = {
24499
+ ApiInstancesNameRoute: ApiInstancesNameRouteWithChildren
24500
+ };
24501
+ const ApiInstancesRouteWithChildren = ApiInstancesRoute._addFileChildren(
24502
+ ApiInstancesRouteChildren
24503
+ );
22547
24504
  const ApiLogsIdRouteChildren = {
22548
24505
  ApiLogsIdBodyRoute,
22549
24506
  ApiLogsIdChunksRoute,
@@ -22621,6 +24578,7 @@ const rootRouteChildren = {
22621
24578
  ApiConfigRoute: ApiConfigRouteWithChildren,
22622
24579
  ApiGroupsRoute: ApiGroupsRouteWithChildren,
22623
24580
  ApiHealthRoute,
24581
+ ApiInstancesRoute: ApiInstancesRouteWithChildren,
22624
24582
  ApiLogsRoute: ApiLogsRouteWithChildren,
22625
24583
  ApiMcpRoute,
22626
24584
  ApiModelsRoute,
@@ -22638,7 +24596,7 @@ const rootRouteChildren = {
22638
24596
  ApiEcosystemRecipesRecipeIdRunRoute,
22639
24597
  ApiKnowledgeSessionsSessionIdCandidatesRoute
22640
24598
  };
22641
- const routeTree = Route$O._addFileChildren(rootRouteChildren)._addFileTypes();
24599
+ const routeTree = Route$U._addFileChildren(rootRouteChildren)._addFileTypes();
22642
24600
  function defaultRouterBasePath() {
22643
24601
  return getRouterBasePath(typeof process === "undefined" ? void 0 : process.env);
22644
24602
  }
@@ -22670,54 +24628,53 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
22670
24628
  getRouter
22671
24629
  }, Symbol.toStringTag, { value: "Module" }));
22672
24630
  export {
22673
- PATH_V1_RESPONSES as $,
24631
+ formatContextWindowInput as $,
22674
24632
  AnthropicResponseSchema$1 as A,
22675
24633
  Button as B,
22676
24634
  CapturedLogSchema as C,
22677
24635
  DEFAULT_CAPTURE_MODE as D,
22678
- getStatusCategory as E,
22679
- stripClaudeCodeBillingHeader as F,
22680
- LazyFeatureBoundary as G,
22681
- AlertSummarySchema as H,
22682
- AlertListResponseSchema as I,
22683
- GroupEvidenceReadResponseSchema as J,
24636
+ stripClaudeCodeBillingHeader as E,
24637
+ LazyFeatureBoundary as F,
24638
+ AlertSummarySchema as G,
24639
+ AlertListResponseSchema as H,
24640
+ GroupEvidenceReadResponseSchema as I,
24641
+ InspectorGroupsListResponseSchema as J,
22684
24642
  KnowledgeCandidateSchema as K,
22685
24643
  LogBodyChunkSchema as L,
22686
- InspectorGroupsListResponseSchema as M,
22687
- DeleteInspectorGroupsResponseSchema as N,
24644
+ DeleteInspectorGroupsResponseSchema as M,
24645
+ GroupEvidenceExportResultSchema as N,
22688
24646
  OpenAIRequestSchema as O,
22689
- GroupEvidenceExportResultSchema as P,
22690
- DeleteInspectorGroupResponseSchema as Q,
22691
- Route$K as R,
24647
+ DeleteInspectorGroupResponseSchema as P,
24648
+ ProviderScanResponseSchema as Q,
24649
+ Route$Q as R,
22692
24650
  SafeRouteError as S,
22693
24651
  THEME_MODE_STORAGE_KEY as T,
22694
24652
  UI_SCALE_STORAGE_KEY as U,
22695
- ProviderScanResponseSchema as V,
22696
- providerHasContextMetadata as W,
22697
- findProviderModelMetadata as X,
22698
- formatContextWindowTokens as Y,
22699
- PATH_V1_MESSAGES as Z,
22700
- PATH_V1_CHAT_COMPLETIONS as _,
24653
+ providerHasContextMetadata as V,
24654
+ findProviderModelMetadata as W,
24655
+ formatContextWindowTokens as X,
24656
+ PATH_V1_MESSAGES as Y,
24657
+ PATH_V1_CHAT_COMPLETIONS as Z,
24658
+ PATH_V1_RESPONSES as _,
22701
24659
  DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
22702
- formatContextWindowInput as a0,
22703
- parseContextWindowTokensInput as a1,
22704
- previewUpstreamUrl as a2,
22705
- createPendingProviderTestResults as a3,
22706
- ProviderTestResultsSchema as a4,
22707
- createFailedProviderTestResults as a5,
22708
- MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as a6,
22709
- MAX_PROVIDER_TEST_TIMEOUT_SECONDS as a7,
22710
- TimeDisplayFormatSchema as a8,
22711
- EcosystemPackagesResponseSchema as a9,
22712
- EcosystemTaskResponseSchema as aa,
22713
- EcosystemTasksResponseSchema as ab,
22714
- EcosystemExecutionConfirmationResponseSchema as ac,
22715
- CrabLogo as ad,
22716
- resolveProviderContextWindow as ae,
22717
- isPlainRecord as af,
22718
- formatUiScale as ag,
22719
- StreamingChunkSchema$1 as ah,
22720
- router as ai,
24660
+ parseContextWindowTokensInput as a0,
24661
+ previewUpstreamUrl as a1,
24662
+ createPendingProviderTestResults as a2,
24663
+ ProviderTestResultsSchema as a3,
24664
+ createFailedProviderTestResults as a4,
24665
+ MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as a5,
24666
+ MAX_PROVIDER_TEST_TIMEOUT_SECONDS as a6,
24667
+ TimeDisplayFormatSchema as a7,
24668
+ EcosystemPackagesResponseSchema as a8,
24669
+ EcosystemTaskResponseSchema as a9,
24670
+ EcosystemTasksResponseSchema as aa,
24671
+ EcosystemExecutionConfirmationResponseSchema as ab,
24672
+ CrabLogo as ac,
24673
+ resolveProviderContextWindow as ad,
24674
+ isPlainRecord as ae,
24675
+ formatUiScale as af,
24676
+ StreamingChunkSchema$1 as ag,
24677
+ router as ah,
22721
24678
  DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
22722
24679
  DEFAULT_TIME_DISPLAY_FORMAT as c,
22723
24680
  RuntimeConfigSchema as d,
@@ -22725,7 +24682,7 @@ export {
22725
24682
  persistThemeMode as f,
22726
24683
  readStoredUiScalePreference as g,
22727
24684
  persistUiScalePreference as h,
22728
- isRecord as i,
24685
+ isRecord$2 as i,
22729
24686
  applyUiScalePreference as j,
22730
24687
  normalizeUiScalePreference as k,
22731
24688
  RedactedProviderDtoSchema as l,
@@ -22739,8 +24696,8 @@ export {
22739
24696
  parseOpenAIResponsesResponse as t,
22740
24697
  OpenAIResponsesRequestSchema as u,
22741
24698
  apiFormatForPath as v,
22742
- withBasePath as w,
22743
- getSessionPath as x,
22744
- formatTokens as y,
22745
- copyTextToClipboard as z
24699
+ getSessionPath as w,
24700
+ formatTokens as x,
24701
+ copyTextToClipboard as y,
24702
+ getStatusCategory as z
22746
24703
  };