@spotpatch/dev-server 0.4.0 → 0.5.0

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.
package/dist/index.cjs CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  createAgentJobManager: () => createAgentJobManager,
37
37
  createIntegrationFileChange: () => createIntegrationFileChange,
38
38
  createRuntimeAiConfig: () => createRuntimeAiConfig,
39
+ createRuntimeDataFlowConfig: () => createRuntimeDataFlowConfig,
39
40
  createSession: () => createSession,
40
41
  createSourceRegistrationService: () => createSourceRegistrationService,
41
42
  createSourceRegistry: () => createSourceRegistry,
@@ -785,7 +786,7 @@ var DEFAULT_EXCLUDE = Object.freeze([
785
786
  /(?:^|\/)dist(?:\/|$)/,
786
787
  /(?:^|\/)coverage(?:\/|$)/
787
788
  ]);
788
- var DEFAULT_INCLUDE = Object.freeze([/(?:^|[/\\])src[/\\].+\.(?:jsx|tsx)$/]);
789
+ var DEFAULT_INCLUDE = Object.freeze([/(?:^|[/\\])src[/\\].+\.(?:js|jsx|ts|tsx)$/]);
789
790
  var DEFAULT_BUDGET = Object.freeze({
790
791
  totalCharacters: 16e3,
791
792
  domCharacters: 3e3,
@@ -806,7 +807,12 @@ var DEFAULT_OPTIONS = Object.freeze({
806
807
  debug: false,
807
808
  locale: "auto",
808
809
  maxTargets: 8,
809
- ai: false
810
+ ai: false,
811
+ dataFlow: Object.freeze({
812
+ enabled: false,
813
+ runtime: "dispatch",
814
+ limits: import_shared2.DEFAULT_DATA_FLOW_LIMITS
815
+ })
810
816
  });
811
817
  var PROFILE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
812
818
  var ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]{1,127}$/;
@@ -1098,6 +1104,36 @@ function assertPositiveBudget(budget) {
1098
1104
  }
1099
1105
  }
1100
1106
  }
1107
+ function resolveDataFlowOptions(options) {
1108
+ if (options === void 0 || options === false) {
1109
+ return DEFAULT_OPTIONS.dataFlow;
1110
+ }
1111
+ const candidate = options;
1112
+ if (typeof candidate !== "object" || candidate === null) {
1113
+ throw new RangeError("SpotPatch dataFlow configuration is invalid.");
1114
+ }
1115
+ const runtime = options.runtime ?? "dispatch";
1116
+ if (runtime !== "dispatch") {
1117
+ throw new RangeError("SpotPatch dataFlow runtime mode is invalid.");
1118
+ }
1119
+ return Object.freeze({
1120
+ enabled: true,
1121
+ runtime,
1122
+ limits: import_shared2.DEFAULT_DATA_FLOW_LIMITS
1123
+ });
1124
+ }
1125
+ function createRuntimeDataFlowConfig(options) {
1126
+ return Object.freeze({
1127
+ enabled: options.enabled,
1128
+ runtime: options.runtime,
1129
+ limits: Object.freeze({
1130
+ observationMaxEntries: options.limits.observationMaxEntries,
1131
+ observationMaxBytes: options.limits.observationMaxBytes,
1132
+ observationTtlMs: options.limits.observationTtlMs,
1133
+ reportMaxBytes: options.limits.reportMaxBytes
1134
+ })
1135
+ });
1136
+ }
1101
1137
  function resolveOptions(options = {}, environmentAi) {
1102
1138
  if (options.trustedFastMode !== void 0 && typeof options.trustedFastMode !== "boolean") {
1103
1139
  throw new RangeError("SpotPatch trustedFastMode must be a boolean.");
@@ -1133,7 +1169,8 @@ function resolveOptions(options = {}, environmentAi) {
1133
1169
  debug: options.debug ?? DEFAULT_OPTIONS.debug,
1134
1170
  locale,
1135
1171
  maxTargets,
1136
- ai: resolveAiOptions(options.ai ?? environmentAi)
1172
+ ai: resolveAiOptions(options.ai ?? environmentAi),
1173
+ dataFlow: resolveDataFlowOptions(options.dataFlow)
1137
1174
  };
1138
1175
  if (resolved.shortcut.trim().length === 0 || resolved.shortcut.length > 128 || resolved.shortcut.includes("\0")) {
1139
1176
  throw new RangeError("SpotPatch shortcut is invalid.");
@@ -1319,33 +1356,58 @@ function createSourceRegistry(options = {}) {
1319
1356
  const createId = options.createId ?? createRandomSourceId;
1320
1357
  const pathToId = /* @__PURE__ */ new Map();
1321
1358
  const idToPath = /* @__PURE__ */ new Map();
1359
+ const componentAnchors = /* @__PURE__ */ new Map();
1360
+ const componentIdsByPath = /* @__PURE__ */ new Map();
1361
+ function registerSourcePath(absolutePath) {
1362
+ const normalizedPath = normalizeAbsolutePath(absolutePath);
1363
+ const existingId = pathToId.get(normalizedPath);
1364
+ if (existingId !== void 0) {
1365
+ return existingId;
1366
+ }
1367
+ let fileId = createId();
1368
+ while (idToPath.has(fileId)) fileId = createId();
1369
+ pathToId.set(normalizedPath, fileId);
1370
+ idToPath.set(fileId, normalizedPath);
1371
+ return fileId;
1372
+ }
1322
1373
  return Object.freeze({
1323
1374
  register(absolutePath) {
1375
+ return registerSourcePath(absolutePath);
1376
+ },
1377
+ registerDataFlowComponents(absolutePath, sourceVersion, components) {
1324
1378
  const normalizedPath = normalizeAbsolutePath(absolutePath);
1325
- const existingId = pathToId.get(normalizedPath);
1326
- if (existingId !== void 0) {
1327
- return existingId;
1379
+ const previousIds = componentIdsByPath.get(normalizedPath);
1380
+ for (const componentSourceId of previousIds ?? []) {
1381
+ componentAnchors.delete(componentSourceId);
1328
1382
  }
1329
- let fileId = createId();
1330
- while (idToPath.has(fileId)) {
1331
- fileId = createId();
1383
+ const fileId = registerSourcePath(normalizedPath);
1384
+ const currentIds = /* @__PURE__ */ new Set();
1385
+ for (const component of components) {
1386
+ currentIds.add(component.componentSourceId);
1387
+ componentAnchors.set(
1388
+ component.componentSourceId,
1389
+ Object.freeze({ ...component, fileId, sourceVersion })
1390
+ );
1332
1391
  }
1333
- pathToId.set(normalizedPath, fileId);
1334
- idToPath.set(fileId, normalizedPath);
1335
- return fileId;
1392
+ componentIdsByPath.set(normalizedPath, currentIds);
1336
1393
  },
1337
1394
  resolve(fileId) {
1338
1395
  return idToPath.get(fileId);
1339
1396
  },
1397
+ resolveDataFlowComponent(componentSourceId) {
1398
+ return componentAnchors.get(componentSourceId);
1399
+ },
1340
1400
  clear() {
1341
1401
  pathToId.clear();
1342
1402
  idToPath.clear();
1403
+ componentAnchors.clear();
1404
+ componentIdsByPath.clear();
1343
1405
  }
1344
1406
  });
1345
1407
  }
1346
1408
 
1347
1409
  // src/server/middleware.ts
1348
- var import_shared10 = require("@spotpatch/shared");
1410
+ var import_shared11 = require("@spotpatch/shared");
1349
1411
 
1350
1412
  // src/server/agent-http.ts
1351
1413
  var import_shared7 = require("@spotpatch/shared");
@@ -2158,10 +2220,177 @@ function createEditorLauncher(dependencies = DEFAULT_DEPENDENCIES2) {
2158
2220
  }
2159
2221
  var launchConfiguredEditor = createEditorLauncher();
2160
2222
 
2161
- // src/server/request-security.ts
2223
+ // src/server/data-flow-http.ts
2162
2224
  var import_node_crypto4 = require("crypto");
2163
- var import_node_net = require("net");
2225
+ var import_analyzer = require("@spotpatch/analyzer");
2164
2226
  var import_shared8 = require("@spotpatch/shared");
2227
+ function envelopeBytes(report) {
2228
+ return Buffer.byteLength(JSON.stringify({ ok: true, data: report }), "utf8");
2229
+ }
2230
+ function limitDataFlowReportToBytes(report, maximumBytes) {
2231
+ const structurallyLimited = (0, import_shared8.limitDataFlowReportCollections)(report);
2232
+ if (envelopeBytes(structurallyLimited) <= maximumBytes) {
2233
+ return structurallyLimited;
2234
+ }
2235
+ let limited = (0, import_shared8.limitDataFlowReportCollections)(structurallyLimited, {
2236
+ forceTruncation: true,
2237
+ maximumDependencies: 0,
2238
+ truncatedBy: "bytes"
2239
+ });
2240
+ if (envelopeBytes(limited) > maximumBytes) {
2241
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INTERNAL_ERROR);
2242
+ }
2243
+ for (let maximumDependencies = 1; maximumDependencies <= structurallyLimited.dependencies.length; maximumDependencies += 1) {
2244
+ const candidate = (0, import_shared8.limitDataFlowReportCollections)(structurallyLimited, {
2245
+ forceTruncation: true,
2246
+ maximumDependencies,
2247
+ truncatedBy: "bytes"
2248
+ });
2249
+ if (envelopeBytes(candidate) > maximumBytes) break;
2250
+ limited = candidate;
2251
+ }
2252
+ return limited;
2253
+ }
2254
+ function createDataFlowAnalyzer(options) {
2255
+ if (!options.options.dataFlow.enabled) return void 0;
2256
+ return (0, import_analyzer.createStaticDataFlowAnalyzer)({
2257
+ root: options.root,
2258
+ registryEpoch: options.session.id,
2259
+ registerSource: (absolutePath) => options.registry.register(absolutePath),
2260
+ limits: options.options.dataFlow.limits
2261
+ });
2262
+ }
2263
+ async function analyzeTarget(request, analyzer, options) {
2264
+ const resolvedRequest = (() => {
2265
+ if ("componentSourceId" in request) {
2266
+ const anchor = options.registry.resolveDataFlowComponent(
2267
+ request.componentSourceId
2268
+ );
2269
+ if (anchor?.sourceVersion !== request.sourceVersion) {
2270
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_SOURCE_STALE);
2271
+ }
2272
+ return anchor;
2273
+ }
2274
+ return request;
2275
+ })();
2276
+ const absolutePath = await resolveSourceFile({
2277
+ fileId: resolvedRequest.fileId,
2278
+ registry: options.registry,
2279
+ root: options.root
2280
+ });
2281
+ const report = analyzer.analyzeComponent({
2282
+ absolutePath,
2283
+ line: resolvedRequest.line,
2284
+ column: resolvedRequest.column
2285
+ });
2286
+ if (resolvedRequest.sourceVersion !== void 0 && resolvedRequest.sourceVersion !== report.component.source.sourceVersion) {
2287
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_SOURCE_STALE);
2288
+ }
2289
+ return limitDataFlowReportToBytes(
2290
+ report,
2291
+ options.options.dataFlow.limits.reportMaxBytes
2292
+ );
2293
+ }
2294
+ function requireAnalyzer(analyzer) {
2295
+ if (analyzer === void 0) {
2296
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_DISABLED);
2297
+ }
2298
+ return analyzer;
2299
+ }
2300
+ async function handleComponentDataFlowReport(request, analyzer, options) {
2301
+ const parsed = import_shared8.dataFlowComponentReportRequestSchema.safeParse(
2302
+ await readJsonRequestBody(
2303
+ request,
2304
+ options.options.dataFlow.limits.protocolRequestMaxBytes
2305
+ )
2306
+ );
2307
+ if (!parsed.success) {
2308
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INVALID_REQUEST);
2309
+ }
2310
+ return analyzeTarget(parsed.data, requireAnalyzer(analyzer), options);
2311
+ }
2312
+ async function handlePageDataFlowReport(request, analyzer, options) {
2313
+ const parsed = import_shared8.dataFlowPageReportRequestSchema.safeParse(
2314
+ await readJsonRequestBody(
2315
+ request,
2316
+ options.options.dataFlow.limits.protocolRequestMaxBytes
2317
+ )
2318
+ );
2319
+ if (!parsed.success) {
2320
+ throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INVALID_REQUEST);
2321
+ }
2322
+ const activeAnalyzer = requireAnalyzer(analyzer);
2323
+ const componentReports = await Promise.all(
2324
+ parsed.data.targets.map((target) => analyzeTarget(target, activeAnalyzer, options))
2325
+ );
2326
+ const dependencies = new Map(
2327
+ componentReports.flatMap(
2328
+ (report2) => report2.dependencies.map((dependency) => [dependency.id, dependency])
2329
+ )
2330
+ );
2331
+ const evidence = new Map(
2332
+ componentReports.flatMap(
2333
+ (report2) => report2.evidence.map((entry) => [entry.id, entry])
2334
+ )
2335
+ );
2336
+ const diagnostics = new Map(
2337
+ componentReports.flatMap(
2338
+ (report2) => report2.diagnostics.map((entry) => [entry.id, entry])
2339
+ )
2340
+ );
2341
+ const analyzedVersions = new Set(
2342
+ componentReports.flatMap((report2) => report2.baseline.analyzedSourceVersions)
2343
+ );
2344
+ const reportId = `page_${(0, import_node_crypto4.createHash)("sha256").update(componentReports.map((report2) => report2.reportId).join("\0")).digest("base64url").slice(0, 22)}`;
2345
+ const complete = componentReports.every((report2) => report2.completeness.complete);
2346
+ const report = Object.freeze({
2347
+ schemaVersion: import_shared8.DATA_FLOW_SCHEMA_VERSION,
2348
+ reportId,
2349
+ baseline: Object.freeze({
2350
+ registryEpoch: options.session.id,
2351
+ analyzerVersion: componentReports[0]?.baseline.analyzerVersion ?? "unavailable",
2352
+ adapterSetHash: componentReports[0]?.baseline.adapterSetHash ?? "unavailable",
2353
+ analyzedSourceVersions: Object.freeze([...analyzedVersions].sort())
2354
+ }),
2355
+ capability: Object.freeze({
2356
+ enabled: true,
2357
+ staticAnalysis: complete ? "available" : "partial",
2358
+ runtimeObservation: "dispatch-only",
2359
+ responseShape: "consumed-fields-only",
2360
+ aiAssistance: "disabled",
2361
+ reasons: Object.freeze(
2362
+ componentReports.flatMap((report2) => report2.capability.reasons)
2363
+ )
2364
+ }),
2365
+ dependencies: Object.freeze([...dependencies.values()]),
2366
+ evidence: Object.freeze([...evidence.values()]),
2367
+ diagnostics: Object.freeze([...diagnostics.values()]),
2368
+ completeness: Object.freeze({
2369
+ complete,
2370
+ visitedModules: componentReports.reduce(
2371
+ (total, report2) => total + report2.completeness.visitedModules,
2372
+ 0
2373
+ ),
2374
+ visitedCallsites: componentReports.reduce(
2375
+ (total, report2) => total + report2.completeness.visitedCallsites,
2376
+ 0
2377
+ ),
2378
+ frontierCount: componentReports.reduce(
2379
+ (total, report2) => total + report2.completeness.frontierCount,
2380
+ 0
2381
+ )
2382
+ })
2383
+ });
2384
+ return limitDataFlowReportToBytes(
2385
+ report,
2386
+ options.options.dataFlow.limits.reportMaxBytes
2387
+ );
2388
+ }
2389
+
2390
+ // src/server/request-security.ts
2391
+ var import_node_crypto5 = require("crypto");
2392
+ var import_node_net = require("net");
2393
+ var import_shared9 = require("@spotpatch/shared");
2165
2394
  function getSingleHeader(request, name) {
2166
2395
  const value = request.headers[name.toLowerCase()];
2167
2396
  return Array.isArray(value) ? value[0] : value;
@@ -2172,7 +2401,7 @@ function tokensMatch(actual, expected) {
2172
2401
  }
2173
2402
  const actualBytes = Buffer.from(actual);
2174
2403
  const expectedBytes = Buffer.from(expected);
2175
- return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto4.timingSafeEqual)(actualBytes, expectedBytes);
2404
+ return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto5.timingSafeEqual)(actualBytes, expectedBytes);
2176
2405
  }
2177
2406
  function isLoopbackHostname(hostname) {
2178
2407
  const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
@@ -2206,32 +2435,32 @@ function parseOrigin(value) {
2206
2435
  }
2207
2436
  }
2208
2437
  function assertRequestAuthorized(request, options) {
2209
- const actualToken = getSingleHeader(request, import_shared8.SPOTPATCH_TOKEN_HEADER);
2438
+ const actualToken = getSingleHeader(request, import_shared9.SPOTPATCH_TOKEN_HEADER);
2210
2439
  if (!tokensMatch(actualToken, options.sessionToken)) {
2211
- throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INVALID_TOKEN);
2440
+ throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.INVALID_TOKEN);
2212
2441
  }
2213
2442
  const hostHeader = getSingleHeader(request, "host");
2214
2443
  const originHeader = getSingleHeader(request, "origin");
2215
2444
  const host = hostHeader === void 0 ? void 0 : parseHost(hostHeader);
2216
2445
  const origin = originHeader === void 0 ? void 0 : parseOrigin(originHeader);
2217
2446
  if (host === void 0 || origin === void 0) {
2218
- throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2447
+ throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2219
2448
  }
2220
2449
  const hostIsLoopback = isLoopbackHostname(host.hostname);
2221
2450
  const originIsLoopback = isLoopbackHostname(origin.hostname);
2222
2451
  if (!options.allowLan) {
2223
2452
  if (!hostIsLoopback || !originIsLoopback) {
2224
- throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2453
+ throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2225
2454
  }
2226
2455
  return;
2227
2456
  }
2228
2457
  if (!originIsLoopback && origin.host.toLowerCase() !== host.host.toLowerCase()) {
2229
- throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2458
+ throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2230
2459
  }
2231
2460
  }
2232
2461
 
2233
2462
  // src/server/runtime-bootstrap.ts
2234
- var import_shared9 = require("@spotpatch/shared");
2463
+ var import_shared10 = require("@spotpatch/shared");
2235
2464
  function getSingleHeader2(request, name) {
2236
2465
  const value = request.headers[name.toLowerCase()];
2237
2466
  return Array.isArray(value) ? value[0] : value;
@@ -2246,7 +2475,7 @@ function resolveRuntimeBootstrapOptions(options) {
2246
2475
  if (expectedOrigin.origin !== options.expectedOrigin || expectedOrigin.protocol !== "http:" || !isLoopbackHostname(expectedOrigin.hostname)) {
2247
2476
  throw new TypeError("The SpotPatch bootstrap origin must be a loopback origin.");
2248
2477
  }
2249
- const parsedConfig = import_shared9.runtimeConfigSchema.safeParse(options.runtimeConfig);
2478
+ const parsedConfig = import_shared10.runtimeConfigSchema.safeParse(options.runtimeConfig);
2250
2479
  if (!parsedConfig.success) {
2251
2480
  throw new TypeError("The SpotPatch Runtime configuration is invalid.");
2252
2481
  }
@@ -2258,7 +2487,7 @@ function resolveRuntimeBootstrapOptions(options) {
2258
2487
  function assertRuntimeBootstrapRequest(request, expectedOrigin) {
2259
2488
  const contentType = getSingleHeader2(request, "content-type")?.split(";", 1)[0]?.trim().toLowerCase();
2260
2489
  if (request.method !== "POST" || contentType !== "application/json") {
2261
- throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.INVALID_REQUEST);
2490
+ throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2262
2491
  }
2263
2492
  const host = getSingleHeader2(request, "host");
2264
2493
  let hostIsLoopback = false;
@@ -2270,90 +2499,96 @@ function assertRuntimeBootstrapRequest(request, expectedOrigin) {
2270
2499
  }
2271
2500
  }
2272
2501
  if (!hostIsLoopback || getSingleHeader2(request, "origin") !== expectedOrigin || getSingleHeader2(request, "sec-fetch-site") !== "same-origin") {
2273
- throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2502
+ throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.ORIGIN_NOT_ALLOWED);
2274
2503
  }
2275
2504
  }
2276
2505
  async function readRuntimeBootstrap(request, options) {
2277
2506
  assertRuntimeBootstrapRequest(request, options.expectedOrigin);
2278
- const parsedBody = import_shared9.runtimeBootstrapRequestSchema.safeParse(
2507
+ const parsedBody = import_shared10.runtimeBootstrapRequestSchema.safeParse(
2279
2508
  await readJsonRequestBody(request)
2280
2509
  );
2281
2510
  if (!parsedBody.success) {
2282
- throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.INVALID_REQUEST);
2511
+ throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2283
2512
  }
2284
2513
  return options.runtimeConfig;
2285
2514
  }
2286
2515
 
2287
2516
  // src/server/middleware.ts
2288
2517
  var STATUS_BY_ERROR = Object.freeze({
2289
- [import_shared10.ERROR_CODES.INVALID_REQUEST]: 400,
2290
- [import_shared10.ERROR_CODES.INVALID_TOKEN]: 401,
2291
- [import_shared10.ERROR_CODES.ORIGIN_NOT_ALLOWED]: 403,
2292
- [import_shared10.ERROR_CODES.SOURCE_NOT_FOUND]: 404,
2293
- [import_shared10.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: 403,
2294
- [import_shared10.ERROR_CODES.SOURCE_TOO_LARGE]: 413,
2295
- [import_shared10.ERROR_CODES.EDITOR_OPEN_FAILED]: 500,
2296
- [import_shared10.ERROR_CODES.AI_DISABLED]: 404,
2297
- [import_shared10.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: 503,
2298
- [import_shared10.ERROR_CODES.PROVIDER_AUTH_FAILED]: 502,
2299
- [import_shared10.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: 502,
2300
- [import_shared10.ERROR_CODES.MODEL_NOT_ALLOWED]: 400,
2301
- [import_shared10.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: 422,
2302
- [import_shared10.ERROR_CODES.PROVIDER_RATE_LIMITED]: 429,
2303
- [import_shared10.ERROR_CODES.AGENT_BUSY]: 409,
2304
- [import_shared10.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: 413,
2305
- [import_shared10.ERROR_CODES.AGENT_CANCELLED]: 409,
2306
- [import_shared10.ERROR_CODES.WORKTREE_DIRTY]: 409,
2307
- [import_shared10.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: 409,
2308
- [import_shared10.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: 409,
2309
- [import_shared10.ERROR_CODES.WORKTREE_CONFLICTED]: 409,
2310
- [import_shared10.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: 413,
2311
- [import_shared10.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: 409,
2312
- [import_shared10.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: 409,
2313
- [import_shared10.ERROR_CODES.TOOL_DENIED]: 403,
2314
- [import_shared10.ERROR_CODES.TOOL_INPUT_INVALID]: 422,
2315
- [import_shared10.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: 422,
2316
- [import_shared10.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: 422,
2317
- [import_shared10.ERROR_CODES.TOOL_PATH_DENIED]: 403,
2318
- [import_shared10.ERROR_CODES.PATCH_REJECTED]: 422,
2319
- [import_shared10.ERROR_CODES.VALIDATION_FAILED]: 422,
2320
- [import_shared10.ERROR_CODES.APPLY_CONFLICT]: 409,
2321
- [import_shared10.ERROR_CODES.INTERNAL_ERROR]: 500
2518
+ [import_shared11.ERROR_CODES.INVALID_REQUEST]: 400,
2519
+ [import_shared11.ERROR_CODES.INVALID_TOKEN]: 401,
2520
+ [import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: 403,
2521
+ [import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: 404,
2522
+ [import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: 403,
2523
+ [import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: 413,
2524
+ [import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: 500,
2525
+ [import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: 404,
2526
+ [import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: 409,
2527
+ [import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: 409,
2528
+ [import_shared11.ERROR_CODES.AI_DISABLED]: 404,
2529
+ [import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: 503,
2530
+ [import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: 502,
2531
+ [import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: 502,
2532
+ [import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: 400,
2533
+ [import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: 422,
2534
+ [import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: 429,
2535
+ [import_shared11.ERROR_CODES.AGENT_BUSY]: 409,
2536
+ [import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: 413,
2537
+ [import_shared11.ERROR_CODES.AGENT_CANCELLED]: 409,
2538
+ [import_shared11.ERROR_CODES.WORKTREE_DIRTY]: 409,
2539
+ [import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: 409,
2540
+ [import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: 409,
2541
+ [import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: 409,
2542
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: 413,
2543
+ [import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: 409,
2544
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: 409,
2545
+ [import_shared11.ERROR_CODES.TOOL_DENIED]: 403,
2546
+ [import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: 422,
2547
+ [import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: 422,
2548
+ [import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: 422,
2549
+ [import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: 403,
2550
+ [import_shared11.ERROR_CODES.PATCH_REJECTED]: 422,
2551
+ [import_shared11.ERROR_CODES.VALIDATION_FAILED]: 422,
2552
+ [import_shared11.ERROR_CODES.APPLY_CONFLICT]: 409,
2553
+ [import_shared11.ERROR_CODES.INTERNAL_ERROR]: 500
2322
2554
  });
2323
2555
  var PUBLIC_MESSAGES = Object.freeze({
2324
- [import_shared10.ERROR_CODES.INVALID_REQUEST]: "The request is invalid.",
2325
- [import_shared10.ERROR_CODES.INVALID_TOKEN]: "The session token is invalid.",
2326
- [import_shared10.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "The request origin is not allowed.",
2327
- [import_shared10.ERROR_CODES.SOURCE_NOT_FOUND]: "The source file is unavailable.",
2328
- [import_shared10.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "The source file is outside the project root.",
2329
- [import_shared10.ERROR_CODES.SOURCE_TOO_LARGE]: "The source file exceeds the size limit.",
2330
- [import_shared10.ERROR_CODES.EDITOR_OPEN_FAILED]: "The editor request could not be started.",
2331
- [import_shared10.ERROR_CODES.AI_DISABLED]: "AI execution is not enabled.",
2332
- [import_shared10.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "The AI provider is unavailable.",
2333
- [import_shared10.ERROR_CODES.PROVIDER_AUTH_FAILED]: "The AI provider rejected authentication.",
2334
- [import_shared10.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "The AI provider protocol is unsupported.",
2335
- [import_shared10.ERROR_CODES.MODEL_NOT_ALLOWED]: "The selected model is not allowed.",
2336
- [import_shared10.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "The selected model cannot run SpotPatch tools.",
2337
- [import_shared10.ERROR_CODES.PROVIDER_RATE_LIMITED]: "The AI provider is rate limited.",
2338
- [import_shared10.ERROR_CODES.AGENT_BUSY]: "Another Agent job is already running.",
2339
- [import_shared10.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "The Agent job exceeded a safety limit.",
2340
- [import_shared10.ERROR_CODES.AGENT_CANCELLED]: "The Agent job was cancelled.",
2341
- [import_shared10.ERROR_CODES.WORKTREE_DIRTY]: "Local changes require explicit inclusion consent.",
2342
- [import_shared10.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "The project root is not a Git repository.",
2343
- [import_shared10.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "A Git operation is currently in progress.",
2344
- [import_shared10.ERROR_CODES.WORKTREE_CONFLICTED]: "The local workspace contains unresolved merge conflicts.",
2345
- [import_shared10.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "The local workspace exceeds the safe isolation size limit.",
2346
- [import_shared10.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path cannot be isolated safely.",
2347
- [import_shared10.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "The local workspace state cannot be isolated safely.",
2348
- [import_shared10.ERROR_CODES.TOOL_DENIED]: "The Agent tool request was denied.",
2349
- [import_shared10.ERROR_CODES.TOOL_INPUT_INVALID]: "The Agent tool input was invalid.",
2350
- [import_shared10.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "The Agent tool arguments are invalid.",
2351
- [import_shared10.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "A tool call ID conflicts within one Agent turn.",
2352
- [import_shared10.ERROR_CODES.TOOL_PATH_DENIED]: "The Agent tool path was denied.",
2353
- [import_shared10.ERROR_CODES.PATCH_REJECTED]: "The proposed patch was rejected.",
2354
- [import_shared10.ERROR_CODES.VALIDATION_FAILED]: "The proposed change failed validation.",
2355
- [import_shared10.ERROR_CODES.APPLY_CONFLICT]: "The change conflicts with the current worktree.",
2356
- [import_shared10.ERROR_CODES.INTERNAL_ERROR]: "The request could not be completed."
2556
+ [import_shared11.ERROR_CODES.INVALID_REQUEST]: "The request is invalid.",
2557
+ [import_shared11.ERROR_CODES.INVALID_TOKEN]: "The session token is invalid.",
2558
+ [import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "The request origin is not allowed.",
2559
+ [import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: "The source file is unavailable.",
2560
+ [import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "The source file is outside the project root.",
2561
+ [import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: "The source file exceeds the size limit.",
2562
+ [import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: "The editor request could not be started.",
2563
+ [import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: "Component data-flow analysis is not enabled.",
2564
+ [import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "The selected source version is stale.",
2565
+ [import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "The data-flow analysis was cancelled.",
2566
+ [import_shared11.ERROR_CODES.AI_DISABLED]: "AI execution is not enabled.",
2567
+ [import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "The AI provider is unavailable.",
2568
+ [import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: "The AI provider rejected authentication.",
2569
+ [import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "The AI provider protocol is unsupported.",
2570
+ [import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: "The selected model is not allowed.",
2571
+ [import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "The selected model cannot run SpotPatch tools.",
2572
+ [import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: "The AI provider is rate limited.",
2573
+ [import_shared11.ERROR_CODES.AGENT_BUSY]: "Another Agent job is already running.",
2574
+ [import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "The Agent job exceeded a safety limit.",
2575
+ [import_shared11.ERROR_CODES.AGENT_CANCELLED]: "The Agent job was cancelled.",
2576
+ [import_shared11.ERROR_CODES.WORKTREE_DIRTY]: "Local changes require explicit inclusion consent.",
2577
+ [import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "The project root is not a Git repository.",
2578
+ [import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "A Git operation is currently in progress.",
2579
+ [import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: "The local workspace contains unresolved merge conflicts.",
2580
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "The local workspace exceeds the safe isolation size limit.",
2581
+ [import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path cannot be isolated safely.",
2582
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "The local workspace state cannot be isolated safely.",
2583
+ [import_shared11.ERROR_CODES.TOOL_DENIED]: "The Agent tool request was denied.",
2584
+ [import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: "The Agent tool input was invalid.",
2585
+ [import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "The Agent tool arguments are invalid.",
2586
+ [import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "A tool call ID conflicts within one Agent turn.",
2587
+ [import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: "The Agent tool path was denied.",
2588
+ [import_shared11.ERROR_CODES.PATCH_REJECTED]: "The proposed patch was rejected.",
2589
+ [import_shared11.ERROR_CODES.VALIDATION_FAILED]: "The proposed change failed validation.",
2590
+ [import_shared11.ERROR_CODES.APPLY_CONFLICT]: "The change conflicts with the current worktree.",
2591
+ [import_shared11.ERROR_CODES.INTERNAL_ERROR]: "The request could not be completed."
2357
2592
  });
2358
2593
  function writeJson(response, status, payload) {
2359
2594
  response.statusCode = status;
@@ -2362,11 +2597,11 @@ function writeJson(response, status, payload) {
2362
2597
  response.end(JSON.stringify(payload));
2363
2598
  }
2364
2599
  function asSpotPatchError(error) {
2365
- return error instanceof import_shared10.SpotPatchError ? error : new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INTERNAL_ERROR, void 0, { cause: error });
2600
+ return error instanceof import_shared11.SpotPatchError ? error : new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INTERNAL_ERROR, void 0, { cause: error });
2366
2601
  }
2367
2602
  function writeError(response, error, logger) {
2368
2603
  const normalized = asSpotPatchError(error);
2369
- if (normalized.code === import_shared10.ERROR_CODES.INTERNAL_ERROR) {
2604
+ if (normalized.code === import_shared11.ERROR_CODES.INTERNAL_ERROR) {
2370
2605
  logger?.warn("[spotpatch:server] Internal request failure.");
2371
2606
  }
2372
2607
  writeJson(response, STATUS_BY_ERROR[normalized.code], {
@@ -2385,11 +2620,11 @@ function requestPath(request) {
2385
2620
  }
2386
2621
  }
2387
2622
  async function handleSourceContext(request, options) {
2388
- const parsed = import_shared10.sourceContextRequestSchema.safeParse(
2623
+ const parsed = import_shared11.sourceContextRequestSchema.safeParse(
2389
2624
  await readJsonRequestBody(request)
2390
2625
  );
2391
2626
  if (!parsed.success) {
2392
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2627
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2393
2628
  }
2394
2629
  return readSourceContext({
2395
2630
  request: parsed.data,
@@ -2400,9 +2635,9 @@ async function handleSourceContext(request, options) {
2400
2635
  });
2401
2636
  }
2402
2637
  async function handleOpenEditor(request, options) {
2403
- const parsed = import_shared10.openEditorRequestSchema.safeParse(await readJsonRequestBody(request));
2638
+ const parsed = import_shared11.openEditorRequestSchema.safeParse(await readJsonRequestBody(request));
2404
2639
  if (!parsed.success) {
2405
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2640
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2406
2641
  }
2407
2642
  const body = parsed.data;
2408
2643
  const sourcePath = await resolveSourceFile({
@@ -2419,22 +2654,23 @@ async function handleOpenEditor(request, options) {
2419
2654
  options.logger?.warn(
2420
2655
  `[spotpatch:server] ${options.options.editor === "auto" ? "The detected editor" : options.options.editor} rejected an editor request.`
2421
2656
  );
2422
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.EDITOR_OPEN_FAILED, void 0, {
2657
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED, void 0, {
2423
2658
  cause: error
2424
2659
  });
2425
2660
  }
2426
2661
  }
2427
2662
  function createSpotPatchMiddleware(options) {
2428
2663
  const bootstrap = options.bootstrap === void 0 ? void 0 : resolveRuntimeBootstrapOptions(options.bootstrap);
2664
+ const dataFlowAnalyzer = createDataFlowAnalyzer(options);
2429
2665
  return (request, response, next) => {
2430
2666
  const path8 = requestPath(request);
2431
2667
  const agentRoute = matchAgentRequestPath(path8);
2432
- if (path8 !== import_shared10.SPOTPATCH_ENDPOINTS.sourceContext && path8 !== import_shared10.SPOTPATCH_ENDPOINTS.openEditor && agentRoute === void 0 && !path8.startsWith(`${import_shared10.SPOTPATCH_API_BASE}/`)) {
2668
+ if (path8 !== import_shared11.SPOTPATCH_ENDPOINTS.sourceContext && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.openEditor && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.dataFlowComponentReport && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.dataFlowPageReport && agentRoute === void 0 && !path8.startsWith(`${import_shared11.SPOTPATCH_API_BASE}/`)) {
2433
2669
  next();
2434
2670
  return;
2435
2671
  }
2436
2672
  const handle = async () => {
2437
- if (path8 === import_shared10.SPOTPATCH_ENDPOINTS.bootstrap && bootstrap !== void 0) {
2673
+ if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.bootstrap && bootstrap !== void 0) {
2438
2674
  const data = await readRuntimeBootstrap(
2439
2675
  request,
2440
2676
  bootstrap
@@ -2446,24 +2682,44 @@ function createSpotPatchMiddleware(options) {
2446
2682
  allowLan: options.options.allowLan,
2447
2683
  sessionToken: options.session.token
2448
2684
  });
2449
- if (path8 === import_shared10.SPOTPATCH_ENDPOINTS.sourceContext) {
2685
+ if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.sourceContext) {
2450
2686
  if (request.method !== "POST") {
2451
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2687
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2452
2688
  }
2453
2689
  const data = await handleSourceContext(request, options);
2454
2690
  writeJson(response, 200, { ok: true, data });
2455
2691
  return;
2456
2692
  }
2457
- if (path8 === import_shared10.SPOTPATCH_ENDPOINTS.openEditor) {
2693
+ if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.openEditor) {
2458
2694
  if (request.method !== "POST") {
2459
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2695
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2460
2696
  }
2461
2697
  const data = await handleOpenEditor(request, options);
2462
2698
  writeJson(response, 200, { ok: true, data });
2463
2699
  return;
2464
2700
  }
2701
+ if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.dataFlowComponentReport) {
2702
+ if (request.method !== "POST") {
2703
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2704
+ }
2705
+ const data = await handleComponentDataFlowReport(
2706
+ request,
2707
+ dataFlowAnalyzer,
2708
+ options
2709
+ );
2710
+ writeJson(response, 200, { ok: true, data });
2711
+ return;
2712
+ }
2713
+ if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.dataFlowPageReport) {
2714
+ if (request.method !== "POST") {
2715
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2716
+ }
2717
+ const data = await handlePageDataFlowReport(request, dataFlowAnalyzer, options);
2718
+ writeJson(response, 200, { ok: true, data });
2719
+ return;
2720
+ }
2465
2721
  if (agentRoute === void 0) {
2466
- throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
2722
+ throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
2467
2723
  }
2468
2724
  await handleAgentRequest(
2469
2725
  request,
@@ -2482,7 +2738,7 @@ function createSpotPatchMiddleware(options) {
2482
2738
  }
2483
2739
 
2484
2740
  // src/server/source-registration.ts
2485
- var import_node_crypto5 = require("crypto");
2741
+ var import_node_crypto6 = require("crypto");
2486
2742
  var import_promises6 = require("fs/promises");
2487
2743
  var import_node_path7 = __toESM(require("path"), 1);
2488
2744
  var import_compiler = require("@spotpatch/compiler");
@@ -2505,7 +2761,7 @@ function identitiesMatch(actual, expected) {
2505
2761
  }
2506
2762
  const actualBytes = Buffer.from(actual);
2507
2763
  const expectedBytes = Buffer.from(expected);
2508
- return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto5.timingSafeEqual)(actualBytes, expectedBytes);
2764
+ return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto6.timingSafeEqual)(actualBytes, expectedBytes);
2509
2765
  }
2510
2766
  function isWithinRoot(root, candidate) {
2511
2767
  const relative = import_node_path7.default.relative(root, candidate);
@@ -2600,11 +2856,11 @@ async function createSourceRegistrationService(input) {
2600
2856
  }
2601
2857
 
2602
2858
  // src/session/session.ts
2603
- var import_node_crypto6 = require("crypto");
2859
+ var import_node_crypto7 = require("crypto");
2604
2860
  function createSession() {
2605
2861
  return Object.freeze({
2606
- id: (0, import_node_crypto6.randomBytes)(16).toString("base64url"),
2607
- token: (0, import_node_crypto6.randomBytes)(16).toString("base64url")
2862
+ id: (0, import_node_crypto7.randomBytes)(16).toString("base64url"),
2863
+ token: (0, import_node_crypto7.randomBytes)(16).toString("base64url")
2608
2864
  });
2609
2865
  }
2610
2866
 
@@ -2614,6 +2870,7 @@ var OPTION_KEYS = Object.freeze([
2614
2870
  "allowLan",
2615
2871
  "budget",
2616
2872
  "debug",
2873
+ "dataFlow",
2617
2874
  "editor",
2618
2875
  "enabled",
2619
2876
  "exclude",
@@ -2701,6 +2958,9 @@ function serializeResolvedSpotPatchOptions(options) {
2701
2958
  allowLan: options.allowLan,
2702
2959
  budget: options.budget,
2703
2960
  debug: options.debug,
2961
+ dataFlow: options.dataFlow.enabled ? Object.freeze({
2962
+ runtime: options.dataFlow.runtime
2963
+ }) : false,
2704
2964
  editor: options.editor,
2705
2965
  enabled: options.enabled,
2706
2966
  exclude: Object.freeze(options.exclude.map(serializeFilter)),
@@ -2743,6 +3003,15 @@ function parseBudget(value) {
2743
3003
  );
2744
3004
  return Object.freeze(budget);
2745
3005
  }
3006
+ function parseDataFlow(value) {
3007
+ if (value === false) return false;
3008
+ if (!isRecord2(value) || !hasExactKeys(value, ["runtime"]) || value.runtime !== "dispatch") {
3009
+ throw new TypeError("The SpotPatch data-flow transport is invalid.");
3010
+ }
3011
+ return Object.freeze({
3012
+ runtime: value.runtime
3013
+ });
3014
+ }
2746
3015
  function parseSerializedSpotPatchOptions(value) {
2747
3016
  if (!isRecord2(value) || !hasExactKeys(value, OPTION_KEYS)) {
2748
3017
  throw new TypeError("The SpotPatch options transport is invalid.");
@@ -2756,6 +3025,7 @@ function parseSerializedSpotPatchOptions(value) {
2756
3025
  allowLan: value.allowLan,
2757
3026
  budget: parseBudget(value.budget),
2758
3027
  debug: value.debug,
3028
+ dataFlow: parseDataFlow(value.dataFlow),
2759
3029
  editor: value.editor,
2760
3030
  enabled: value.enabled,
2761
3031
  exclude: parseFilterList(value.exclude),
@@ -2779,6 +3049,7 @@ function parseSerializedSpotPatchOptions(value) {
2779
3049
  createAgentJobManager,
2780
3050
  createIntegrationFileChange,
2781
3051
  createRuntimeAiConfig,
3052
+ createRuntimeDataFlowConfig,
2782
3053
  createSession,
2783
3054
  createSourceRegistrationService,
2784
3055
  createSourceRegistry,