ue-mcp 1.2.1 → 1.2.2

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 (54) hide show
  1. package/dist/context-cli.js +16 -16
  2. package/dist/engine-observer.js +68 -68
  3. package/dist/flow/guard.d.ts +26 -37
  4. package/dist/flow/guard.js +40 -25
  5. package/dist/flow/guard.js.map +1 -1
  6. package/dist/flow/guarded-bridge.d.ts +0 -10
  7. package/dist/flow/guarded-bridge.js +18 -23
  8. package/dist/flow/guarded-bridge.js.map +1 -1
  9. package/dist/flow/schema.d.ts +276 -16
  10. package/dist/flow/task-guards.d.ts +1 -1
  11. package/dist/flow/task-guards.js +44 -68
  12. package/dist/flow/task-guards.js.map +1 -1
  13. package/dist/instructions.js +130 -130
  14. package/dist/plugin-cli.js +299 -299
  15. package/dist/tool-counts.json +2 -2
  16. package/package.json +2 -2
  17. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.cpp +76 -76
  18. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.h +27 -27
  19. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.cpp +128 -128
  20. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.h +63 -63
  21. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +230 -230
  22. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +323 -323
  23. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +20 -20
  24. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +537 -537
  25. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.h +77 -77
  26. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +353 -353
  27. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +18 -18
  28. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_InputRuntime.cpp +246 -246
  29. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +597 -597
  30. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +51 -51
  31. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +878 -878
  32. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +449 -449
  33. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Function.cpp +275 -275
  34. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Graph.cpp +551 -551
  35. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +531 -531
  36. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.h +28 -28
  37. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +677 -677
  38. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +822 -822
  39. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +22 -22
  40. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +218 -218
  41. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.h +17 -17
  42. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.cpp +46 -46
  43. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.h +23 -23
  44. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/MCPExternalRegistry.cpp +83 -83
  45. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/UE_MCP_BridgeModule.h +14 -14
  46. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/UE_MCP_BridgeStatusModule.cpp +37 -37
  47. package/dist/manifest-signature.d.ts +0 -1
  48. package/dist/manifest-signature.js +0 -53
  49. package/dist/manifest-signature.js.map +0 -1
  50. package/dist/pie/schema.d.ts +0 -791
  51. package/dist/pie/schema.js +0 -151
  52. package/dist/pie/schema.js.map +0 -1
  53. package/dist/watch-cli.js.map +0 -1
  54. /package/plugin/ue_mcp_bridge/{ue_mcp_bridge.uplugin → UE_MCP_Bridge.uplugin} +0 -0
@@ -21,20 +21,20 @@ const CYAN = "\x1b[36m";
21
21
  const YELLOW = "\x1b[33m";
22
22
  const ACTIONS = new Set(["full", "lean", "micro", "status"]);
23
23
  function printHelp() {
24
- console.log(`
25
- ${BOLD}${CYAN}ue-mcp context${RESET} - control the context seeding strategy
26
-
27
- ${BOLD}Usage:${RESET}
28
- ue-mcp context show the current strategy
29
- ue-mcp context status show the current strategy
30
- ue-mcp context full every action inline (largest seed, default)
31
- ue-mcp context lean action names visible, descriptions on demand
32
- ue-mcp context micro one gateway tool fronts everything (smallest)
33
-
34
- A project path may be passed as the last argument, or an editor named with
35
- --editor <name-or-path>; otherwise the .uproject in the current directory is
36
- used. Restart your MCP client (/mcp in Claude Code) after changing the
37
- strategy.
24
+ console.log(`
25
+ ${BOLD}${CYAN}ue-mcp context${RESET} - control the context seeding strategy
26
+
27
+ ${BOLD}Usage:${RESET}
28
+ ue-mcp context show the current strategy
29
+ ue-mcp context status show the current strategy
30
+ ue-mcp context full every action inline (largest seed, default)
31
+ ue-mcp context lean action names visible, descriptions on demand
32
+ ue-mcp context micro one gateway tool fronts everything (smallest)
33
+
34
+ A project path may be passed as the last argument, or an editor named with
35
+ --editor <name-or-path>; otherwise the .uproject in the current directory is
36
+ used. Restart your MCP client (/mcp in Claude Code) after changing the
37
+ strategy.
38
38
  `);
39
39
  }
40
40
  function parseArgs() {
@@ -50,8 +50,8 @@ function parseArgs() {
50
50
  target = takeEditorTarget(argv);
51
51
  }
52
52
  catch (e) {
53
- console.log(`
54
- ${RED}${e instanceof EditorFlagError ? e.message : String(e)}${RESET}
53
+ console.log(`
54
+ ${RED}${e instanceof EditorFlagError ? e.message : String(e)}${RESET}
55
55
  `);
56
56
  process.exit(1);
57
57
  }
@@ -65,19 +65,19 @@ function classify(pid, commandLine, responding, windowTitle) {
65
65
  // seconds (interpreter start ~1.5s, CIM ~4s, and `tasklist` is no cheaper), so
66
66
  // the whole probe is a single script and callers reach it only when the fast
67
67
  // signal - the bridge socket itself - has already failed.
68
- const WINDOWS_PROCESS_SCRIPT = `
69
- $ErrorActionPreference = 'SilentlyContinue'
70
- $procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'UnrealEditor%'"
71
- $out = foreach ($p in $procs) {
72
- $ps = Get-Process -Id $p.ProcessId -ErrorAction SilentlyContinue
73
- [pscustomobject]@{
74
- pid = $p.ProcessId
75
- cmd = $p.CommandLine
76
- responding = $(if ($ps) { [bool]$ps.Responding } else { $true })
77
- title = $(if ($ps) { $ps.MainWindowTitle } else { '' })
78
- }
79
- }
80
- @($out) | ConvertTo-Json -Compress -Depth 3
68
+ const WINDOWS_PROCESS_SCRIPT = `
69
+ $ErrorActionPreference = 'SilentlyContinue'
70
+ $procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'UnrealEditor%'"
71
+ $out = foreach ($p in $procs) {
72
+ $ps = Get-Process -Id $p.ProcessId -ErrorAction SilentlyContinue
73
+ [pscustomobject]@{
74
+ pid = $p.ProcessId
75
+ cmd = $p.CommandLine
76
+ responding = $(if ($ps) { [bool]$ps.Responding } else { $true })
77
+ title = $(if ($ps) { $ps.MainWindowTitle } else { '' })
78
+ }
79
+ }
80
+ @($out) | ConvertTo-Json -Compress -Depth 3
81
81
  `;
82
82
  // The process table is polled from wait loops and status calls; a short TTL
83
83
  // keeps a burst of callers from paying for the same query repeatedly, while
@@ -297,61 +297,61 @@ export function readLogState(projectPath, tailLines = 25) {
297
297
  * so it can be read from outside even when the process is not pumping. This is
298
298
  * the only way to see a dialog that appears before the plugin loads.
299
299
  */
300
- const WINDOWS_DIALOG_SCRIPT = `
301
- $ErrorActionPreference = 'SilentlyContinue'
302
- $sig = @'
303
- using System;
304
- using System.Text;
305
- using System.Runtime.InteropServices;
306
- public class UeMcpWin {
307
- public delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
308
- [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p);
309
- [DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr h, EnumProc cb, IntPtr p);
310
- [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
311
- [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
312
- [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
313
- [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
314
- [DllImport("user32.dll")] public static extern bool IsHungAppWindow(IntPtr h);
315
- public static string Text(IntPtr h) {
316
- StringBuilder sb = new StringBuilder(1024);
317
- GetWindowTextW(h, sb, sb.Capacity);
318
- return sb.ToString();
319
- }
320
- public static string Cls(IntPtr h) {
321
- StringBuilder sb = new StringBuilder(256);
322
- GetClassNameW(h, sb, sb.Capacity);
323
- return sb.ToString();
324
- }
325
- }
326
- '@
327
- Add-Type -TypeDefinition $sig -Language CSharp | Out-Null
328
- $targetPids = @(__PIDS__)
329
- $results = New-Object System.Collections.ArrayList
330
- $top = [UeMcpWin+EnumProc]{
331
- param($h, $l)
332
- $procId = 0
333
- [void][UeMcpWin]::GetWindowThreadProcessId($h, [ref]$procId)
334
- if ($targetPids -contains [int]$procId -and [UeMcpWin]::IsWindowVisible($h)) {
335
- $children = New-Object System.Collections.ArrayList
336
- $child = [UeMcpWin+EnumProc]{
337
- param($c, $cl)
338
- $t = [UeMcpWin]::Text($c)
339
- if ($t -and $t.Trim().Length -gt 0) { [void]$children.Add($t) }
340
- return $true
341
- }
342
- [void][UeMcpWin]::EnumChildWindows($h, $child, [IntPtr]::Zero)
343
- [void]$results.Add([pscustomobject]@{
344
- handle = $h.ToString()
345
- className = [UeMcpWin]::Cls($h)
346
- title = [UeMcpWin]::Text($h)
347
- text = @($children)
348
- hung = [bool][UeMcpWin]::IsHungAppWindow($h)
349
- })
350
- }
351
- return $true
352
- }
353
- [void][UeMcpWin]::EnumWindows($top, [IntPtr]::Zero)
354
- @($results) | ConvertTo-Json -Compress -Depth 4
300
+ const WINDOWS_DIALOG_SCRIPT = `
301
+ $ErrorActionPreference = 'SilentlyContinue'
302
+ $sig = @'
303
+ using System;
304
+ using System.Text;
305
+ using System.Runtime.InteropServices;
306
+ public class UeMcpWin {
307
+ public delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
308
+ [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p);
309
+ [DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr h, EnumProc cb, IntPtr p);
310
+ [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
311
+ [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
312
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
313
+ [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
314
+ [DllImport("user32.dll")] public static extern bool IsHungAppWindow(IntPtr h);
315
+ public static string Text(IntPtr h) {
316
+ StringBuilder sb = new StringBuilder(1024);
317
+ GetWindowTextW(h, sb, sb.Capacity);
318
+ return sb.ToString();
319
+ }
320
+ public static string Cls(IntPtr h) {
321
+ StringBuilder sb = new StringBuilder(256);
322
+ GetClassNameW(h, sb, sb.Capacity);
323
+ return sb.ToString();
324
+ }
325
+ }
326
+ '@
327
+ Add-Type -TypeDefinition $sig -Language CSharp | Out-Null
328
+ $targetPids = @(__PIDS__)
329
+ $results = New-Object System.Collections.ArrayList
330
+ $top = [UeMcpWin+EnumProc]{
331
+ param($h, $l)
332
+ $procId = 0
333
+ [void][UeMcpWin]::GetWindowThreadProcessId($h, [ref]$procId)
334
+ if ($targetPids -contains [int]$procId -and [UeMcpWin]::IsWindowVisible($h)) {
335
+ $children = New-Object System.Collections.ArrayList
336
+ $child = [UeMcpWin+EnumProc]{
337
+ param($c, $cl)
338
+ $t = [UeMcpWin]::Text($c)
339
+ if ($t -and $t.Trim().Length -gt 0) { [void]$children.Add($t) }
340
+ return $true
341
+ }
342
+ [void][UeMcpWin]::EnumChildWindows($h, $child, [IntPtr]::Zero)
343
+ [void]$results.Add([pscustomobject]@{
344
+ handle = $h.ToString()
345
+ className = [UeMcpWin]::Cls($h)
346
+ title = [UeMcpWin]::Text($h)
347
+ text = @($children)
348
+ hung = [bool][UeMcpWin]::IsHungAppWindow($h)
349
+ })
350
+ }
351
+ return $true
352
+ }
353
+ [void][UeMcpWin]::EnumWindows($top, [IntPtr]::Zero)
354
+ @($results) | ConvertTo-Json -Compress -Depth 4
355
355
  `;
356
356
  /**
357
357
  * Visible top-level windows belonging to the given PIDs, with their child text.
@@ -1,26 +1,26 @@
1
1
  /**
2
- * A general guard pipeline around the editor bridge, in the shape of NestJS
3
- * guards/interceptors but agnostic to what any guard does.
2
+ * The bridge's binding of flowkit's guard pipeline.
4
3
  *
5
- * Every mutating and non-mutating action crosses `IBridge.call`. A `GuardedBridge`
6
- * runs a registry of `BridgeGuard`s on that seam: each guard may inspect the call,
7
- * run a `before` hook that can veto it (throw) or act on it (e.g. check a file
8
- * out), and an optional `after` hook that can observe or replace the result
9
- * (audit, transform). The chain itself knows nothing about source control,
10
- * policy, rate limiting, or any concrete concern - those are guards.
4
+ * Every mutating and non-mutating action crosses `IBridge.call`. That seam is
5
+ * guarded: each guard may inspect the call, run a `before` hook that can veto
6
+ * it (throw) or act on it (e.g. check a file out), and an `after` hook that can
7
+ * observe or replace the result. The chain itself knows nothing about source
8
+ * control, policy, rate limiting, or any concrete concern - those are guards.
11
9
  *
12
- * `CallContext` is the per-call execution context handed to guards. It carries
13
- * the raw method/params and a lazy enrichment layer (`write()` / `writeFiles()`)
14
- * that write-oriented guards may consult, computed on demand and cached so a
15
- * guard that ignores writes pays nothing.
10
+ * The pipeline, its ordering, and the `guard.<name>.<phase>` task convention
11
+ * live in `@db-lyon/flowkit/guard`, because none of that is about Unreal. What
12
+ * stays here is what is: the shape of a bridge call, and the write
13
+ * classification in `write-methods.ts` that decides which content paths a call
14
+ * is about to modify.
16
15
  */
16
+ import { GuardRegistry as FlowkitGuardRegistry, type Guard, type GuardContext } from "@db-lyon/flowkit/guard";
17
17
  import type { IBridge } from "../bridge.js";
18
18
  import type { EditorSession } from "../session.js";
19
19
  import { type WriteClassification } from "./write-methods.js";
20
20
  /** Resolve a UE content path to an absolute on-disk file, or null if it does not exist. */
21
21
  export type ResolveExistingFile = (contentPath: string) => string | null;
22
- /** Per-call execution context passed to every guard. Analogous to a NestJS ExecutionContext. */
23
- export interface CallContext {
22
+ /** Per-call execution context passed to every guard. */
23
+ export interface CallContext extends GuardContext {
24
24
  readonly method: string;
25
25
  readonly params: Record<string, unknown>;
26
26
  readonly timeoutMs?: number;
@@ -28,36 +28,25 @@ export interface CallContext {
28
28
  readonly bridge: IBridge;
29
29
  /** The editor this call is bound to. Absent only for a bridge built outside a session. */
30
30
  readonly session?: EditorSession;
31
- /** Scratch space shared across guards for the life of one call. */
32
- readonly meta: Map<string, unknown>;
33
31
  /** Lazy: how this call classifies as a write (which content paths it touches). Cached. */
34
32
  write(): WriteClassification;
35
33
  /** Lazy: absolute, existing on-disk files this call will modify (subset of write paths). Cached. */
36
34
  writeFiles(): string[];
37
35
  }
38
36
  /**
39
- * A guard on the bridge pipeline. Any of the hooks is optional. Guards are
40
- * agnostic: source control, access policy, audit, rate limiting, and approval
41
- * gating are all just guards.
37
+ * A guard on the bridge pipeline. Guards are agnostic: source control, access
38
+ * policy, audit, rate limiting, and approval gating are all just guards.
42
39
  */
43
- export interface BridgeGuard {
44
- /** Stable identifier, for logging and ordering ties. */
45
- readonly name: string;
46
- /** Lower runs first in `before` and last in `after`. Default 0. */
47
- readonly order?: number;
48
- /** Whether this guard participates for a given call. Default: always. */
49
- appliesTo?(ctx: CallContext): boolean | Promise<boolean>;
50
- /** Runs before the call. Throw to DENY the call; side effects are allowed. */
51
- before?(ctx: CallContext): Promise<void>;
52
- /** Runs after a successful call. Return a value to replace the result; return nothing to leave it. */
53
- after?(ctx: CallContext, result: unknown): Promise<unknown | void>;
54
- }
55
- /** An ordered set of guards. Built-in guards register directly; plugin guards are discovered. */
56
- export declare class GuardRegistry {
57
- private guards;
58
- register(guard: BridgeGuard): this;
59
- list(): readonly BridgeGuard[];
60
- get size(): number;
40
+ export type BridgeGuard = Guard<CallContext, unknown>;
41
+ /** The bridge's guard set. Built-in guards register directly; plugin guards are discovered. */
42
+ export declare class GuardRegistry extends FlowkitGuardRegistry<CallContext, unknown> {
61
43
  }
44
+ /**
45
+ * The scope a `guard.<name>.<phase>Write` task binds to: the call resolves to
46
+ * existing on-disk files it is about to modify. Declared here rather than in
47
+ * the task layer so the hand-written and task-backed guards agree on what
48
+ * "write" means.
49
+ */
50
+ export declare function writeScope(ctx: CallContext): boolean;
62
51
  /** Build the per-call context, wiring the lazy write-enrichment helpers. */
63
52
  export declare function makeCallContext(method: string, params: Record<string, unknown>, timeoutMs: number | undefined, rawBridge: IBridge, resolveExistingFile: ResolveExistingFile, session?: EditorSession): CallContext;
@@ -1,34 +1,49 @@
1
+ /**
2
+ * The bridge's binding of flowkit's guard pipeline.
3
+ *
4
+ * Every mutating and non-mutating action crosses `IBridge.call`. That seam is
5
+ * guarded: each guard may inspect the call, run a `before` hook that can veto
6
+ * it (throw) or act on it (e.g. check a file out), and an `after` hook that can
7
+ * observe or replace the result. The chain itself knows nothing about source
8
+ * control, policy, rate limiting, or any concrete concern - those are guards.
9
+ *
10
+ * The pipeline, its ordering, and the `guard.<name>.<phase>` task convention
11
+ * live in `@db-lyon/flowkit/guard`, because none of that is about Unreal. What
12
+ * stays here is what is: the shape of a bridge call, and the write
13
+ * classification in `write-methods.ts` that decides which content paths a call
14
+ * is about to modify.
15
+ */
16
+ import { GuardRegistry as FlowkitGuardRegistry, guardContextBase, lazy, } from "@db-lyon/flowkit/guard";
1
17
  import { classifyWrite } from "./write-methods.js";
2
- /** An ordered set of guards. Built-in guards register directly; plugin guards are discovered. */
3
- export class GuardRegistry {
4
- guards = [];
5
- register(guard) {
6
- this.guards.push(guard);
7
- // Stable order: by `order`, then by name for determinism.
8
- this.guards.sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name));
9
- return this;
10
- }
11
- list() {
12
- return this.guards;
13
- }
14
- get size() {
15
- return this.guards.length;
16
- }
18
+ /** The bridge's guard set. Built-in guards register directly; plugin guards are discovered. */
19
+ export class GuardRegistry extends FlowkitGuardRegistry {
20
+ }
21
+ /**
22
+ * The scope a `guard.<name>.<phase>Write` task binds to: the call resolves to
23
+ * existing on-disk files it is about to modify. Declared here rather than in
24
+ * the task layer so the hand-written and task-backed guards agree on what
25
+ * "write" means.
26
+ */
27
+ export function writeScope(ctx) {
28
+ return ctx.writeFiles().length > 0;
17
29
  }
18
30
  /** Build the per-call context, wiring the lazy write-enrichment helpers. */
19
31
  export function makeCallContext(method, params, timeoutMs, rawBridge, resolveExistingFile, session) {
20
- let writeCache;
21
- let filesCache;
22
- const write = () => (writeCache ??= classifyWrite(method, params));
23
- const writeFiles = () => {
24
- if (filesCache)
25
- return filesCache;
32
+ const ctx = {
33
+ ...guardContextBase(),
34
+ method,
35
+ params,
36
+ timeoutMs,
37
+ bridge: rawBridge,
38
+ session,
39
+ };
40
+ const write = lazy(ctx, "write", () => classifyWrite(method, params));
41
+ const writeFiles = lazy(ctx, "writeFiles", () => {
26
42
  const c = write();
27
- filesCache = c.writes
43
+ return c.writes
28
44
  ? c.contentPaths.map(resolveExistingFile).filter((f) => f !== null)
29
45
  : [];
30
- return filesCache;
31
- };
32
- return { method, params, timeoutMs, bridge: rawBridge, session, meta: new Map(), write, writeFiles };
46
+ });
47
+ return Object.assign(ctx, { write, writeFiles });
33
48
  }
34
49
  //# sourceMappingURL=guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/flow/guard.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,aAAa,EAA4B,MAAM,oBAAoB,CAAC;AAwC7E,iGAAiG;AACjG,MAAM,OAAO,aAAa;IAChB,MAAM,GAAkB,EAAE,CAAC;IAEnC,QAAQ,CAAC,KAAkB;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,0DAA0D;QAC1D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,MAA+B,EAC/B,SAA6B,EAC7B,SAAkB,EAClB,mBAAwC,EACxC,OAAuB;IAEvB,IAAI,UAA2C,CAAC;IAChD,IAAI,UAAgC,CAAC;IAErC,MAAM,KAAK,GAAG,GAAwB,EAAE,CAAC,CAAC,UAAU,KAAK,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxF,MAAM,UAAU,GAAG,GAAa,EAAE;QAChC,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;QAClC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;QAClB,UAAU,GAAG,CAAC,CAAC,MAAM;YACnB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;YAChF,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACvG,CAAC"}
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/flow/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,aAAa,IAAI,oBAAoB,EACrC,gBAAgB,EAChB,IAAI,GAGL,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,aAAa,EAA4B,MAAM,oBAAoB,CAAC;AA0B7E,+FAA+F;AAC/F,MAAM,OAAO,aAAc,SAAQ,oBAA0C;CAAG;AAEhF;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAgB;IACzC,OAAO,GAAG,CAAC,UAAU,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,MAA+B,EAC/B,SAA6B,EAC7B,SAAkB,EAClB,mBAAwC,EACxC,OAAuB;IAEvB,MAAM,GAAG,GAAG;QACV,GAAG,gBAAgB,EAAE;QACrB,MAAM;QACN,MAAM;QACN,SAAS;QACT,MAAM,EAAE,SAAS;QACjB,OAAO;KACO,CAAC;IAEjB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,CAAC,MAAM;YACb,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;YAChF,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;AACnD,CAAC"}
@@ -1,13 +1,3 @@
1
- /**
2
- * GuardedBridge - runs a `GuardRegistry` pipeline around the editor bridge.
3
- *
4
- * Before a call reaches Unreal, each applicable guard's `before` hook runs in
5
- * order (any may throw to deny). After a successful call, each guard's `after`
6
- * hook runs in reverse order and may replace the result. With an empty registry
7
- * this is a pure pass-through, so it is always safe to install.
8
- *
9
- * Only `call` is gated; connection lifecycle delegates straight through.
10
- */
11
1
  import type { BridgeTarget, IBridge } from "../bridge.js";
12
2
  import type { EditorSession } from "../session.js";
13
3
  import { GuardRegistry, type ResolveExistingFile } from "./guard.js";
@@ -1,4 +1,17 @@
1
- import { makeCallContext, } from "./guard.js";
1
+ /**
2
+ * GuardedBridge - runs a `GuardRegistry` pipeline around the editor bridge.
3
+ *
4
+ * Before a call reaches Unreal, each applicable guard's `before` hook runs in
5
+ * order (any may throw to deny). After a successful call, each guard's `after`
6
+ * hook runs in reverse order and may replace the result. With an empty registry
7
+ * this is a pure pass-through, so it is always safe to install.
8
+ *
9
+ * The pipeline itself is `runGuarded` from flowkit; what this class adds is the
10
+ * `IBridge` shape. Only `call` is gated; connection lifecycle delegates
11
+ * straight through.
12
+ */
13
+ import { runGuarded } from "@db-lyon/flowkit/guard";
14
+ import { makeCallContext } from "./guard.js";
2
15
  export class GuardedBridge {
3
16
  inner;
4
17
  registry;
@@ -26,32 +39,14 @@ export class GuardedBridge {
26
39
  return this.inner.getTarget();
27
40
  }
28
41
  async call(method, params, timeoutMs) {
42
+ // `runGuarded` is already a pass-through on an empty registry, but building
43
+ // the context is not free and every bridge call lands here. Most servers run
44
+ // with no guards at all, so skip the allocation outright.
29
45
  if (this.registry.size === 0) {
30
46
  return this.inner.call(method, params, timeoutMs);
31
47
  }
32
48
  const ctx = makeCallContext(method, params ?? {}, timeoutMs, this.inner, this.resolveExistingFile, this.session);
33
- // Resolve applicability once so `before`/`after` see a consistent set.
34
- const applicable = [];
35
- for (const g of this.registry.list()) {
36
- if (!g.appliesTo || (await g.appliesTo(ctx)))
37
- applicable.push(g);
38
- }
39
- // before: in order. A throw denies the call and propagates unchanged.
40
- for (const g of applicable) {
41
- if (g.before)
42
- await g.before(ctx);
43
- }
44
- let result = await this.inner.call(method, params, timeoutMs);
45
- // after: in reverse order. A returned value replaces the result.
46
- for (let i = applicable.length - 1; i >= 0; i--) {
47
- const g = applicable[i];
48
- if (g.after) {
49
- const replaced = await g.after(ctx, result);
50
- if (replaced !== undefined)
51
- result = replaced;
52
- }
53
- }
54
- return result;
49
+ return runGuarded(ctx, this.registry, () => this.inner.call(method, params, timeoutMs));
55
50
  }
56
51
  }
57
52
  //# sourceMappingURL=guarded-bridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"guarded-bridge.js","sourceRoot":"","sources":["../../src/flow/guarded-bridge.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,eAAe,GAGhB,MAAM,YAAY,CAAC;AAIpB,MAAM,OAAO,aAAa;IAEL;IACA;IACA;IAGA;IANnB,YACmB,KAAc,EACd,QAAuB,EACvB,mBAAwC;IACzD;2EACuE;IACtD,OAAuB;QALvB,UAAK,GAAL,KAAK,CAAS;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,wBAAmB,GAAnB,mBAAmB,CAAqB;QAGxC,YAAO,GAAP,OAAO,CAAgB;IACvC,CAAC;IAEJ,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,SAAkB;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,eAAe,CAAC,YAAoB,EAAE,UAAmB;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAI,CACR,MAAc,EACd,MAAgC,EAChC,SAAkB;QAElB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjH,uEAAuE;QACvE,MAAM,UAAU,GAAkB,EAAE,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;QAED,sEAAsE;QACtE,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,MAAM;gBAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAE9D,iEAAiE;QACjE,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACZ,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC5C,IAAI,QAAQ,KAAK,SAAS;oBAAE,MAAM,GAAG,QAAQ,CAAC;YAChD,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
1
+ {"version":3,"file":"guarded-bridge.js","sourceRoot":"","sources":["../../src/flow/guarded-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,OAAO,EAAiB,eAAe,EAA4B,MAAM,YAAY,CAAC;AAItF,MAAM,OAAO,aAAa;IAEL;IACA;IACA;IAGA;IANnB,YACmB,KAAc,EACd,QAAuB,EACvB,mBAAwC;IACzD;2EACuE;IACtD,OAAuB;QALvB,UAAK,GAAL,KAAK,CAAS;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,wBAAmB,GAAnB,mBAAmB,CAAqB;QAGxC,YAAO,GAAP,OAAO,CAAgB;IACvC,CAAC;IAEJ,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,SAAkB;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,eAAe,CAAC,YAAoB,EAAE,UAAmB;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAI,CACR,MAAc,EACd,MAAgC,EAChC,SAAkB;QAElB,4EAA4E;QAC5E,6EAA6E;QAC7E,0DAA0D;QAC1D,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,eAAe,CACzB,MAAM,EACN,MAAM,IAAI,EAAE,EACZ,SAAS,EACT,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,OAAO,CACb,CAAC;QACF,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC1F,CAAC;CACF"}