ue-mcp 1.1.16 → 1.1.18

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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/editor-control.js +27 -5
  3. package/dist/editor-control.js.map +1 -1
  4. package/dist/errors.d.ts +4 -1
  5. package/dist/errors.js +3 -0
  6. package/dist/errors.js.map +1 -1
  7. package/dist/flow/guard.d.ts +60 -0
  8. package/dist/flow/guard.js +34 -0
  9. package/dist/flow/guard.js.map +1 -0
  10. package/dist/flow/guarded-bridge.d.ts +22 -0
  11. package/dist/flow/guarded-bridge.js +46 -0
  12. package/dist/flow/guarded-bridge.js.map +1 -0
  13. package/dist/flow/task-guards.d.ts +13 -0
  14. package/dist/flow/task-guards.js +98 -0
  15. package/dist/flow/task-guards.js.map +1 -0
  16. package/dist/flow/write-methods.d.ts +34 -0
  17. package/dist/flow/write-methods.js +85 -0
  18. package/dist/flow/write-methods.js.map +1 -0
  19. package/dist/index.js +20 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/instructions.d.ts +3 -3
  22. package/dist/instructions.js +4 -4
  23. package/dist/lean-context.d.ts +2 -2
  24. package/dist/lean-context.js +1 -1
  25. package/dist/tool-counts.json +7 -6
  26. package/dist/tools/fab.d.ts +2 -0
  27. package/dist/tools/fab.js +29 -0
  28. package/dist/tools/fab.js.map +1 -0
  29. package/dist/tools.js +2 -0
  30. package/dist/tools.js.map +1 -1
  31. package/package.json +2 -2
  32. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +2 -0
  33. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_MotionMatching.cpp +6 -0
  34. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +7 -0
  35. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +3 -1
  36. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers.cpp +24 -6
  37. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FabHandlers.cpp +244 -0
  38. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FabHandlers.h +33 -0
  39. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +15 -0
  40. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +18 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # UE-MCP
2
2
 
3
- **Unreal Engine Model Context Protocol Server** - gives AI assistants deep read/write access to the Unreal Editor through <!-- count:tools -->23<!-- /count --> category tools covering <!-- count:actions -->711+<!-- /count --> actions, plus a YAML flow engine for multi-step workflows.
3
+ **Unreal Engine Model Context Protocol Server** - gives AI assistants deep read/write access to the Unreal Editor through <!-- count:tools -->24<!-- /count --> category tools covering <!-- count:actions -->719+<!-- /count --> actions, plus a YAML flow engine for multi-step workflows.
4
4
 
5
5
  ```mermaid
6
6
  flowchart LR
@@ -7,12 +7,34 @@ import { findEngineInstall } from "./deployer.js";
7
7
  // The MCP server itself is cross-platform; only process control is gated.
8
8
  const IS_WINDOWS = process.platform === "win32";
9
9
  const WINDOWS_ONLY_MSG = "editor start/stop/restart is Windows-only. On macOS/Linux, start and stop the Unreal Editor manually; ue-mcp will reconnect when the bridge is reachable.";
10
- function findUEBuildTool() {
10
+ /** Read EngineAssociation from a .uproject, or null if unreadable. */
11
+ function readEngineAssociation(projectPath) {
12
+ try {
13
+ const parsed = JSON.parse(fs.readFileSync(projectPath, "utf-8"));
14
+ return typeof parsed?.EngineAssociation === "string" ? parsed.EngineAssociation : null;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ function findUEBuildTool(engineAssociation) {
11
21
  const envPath = process.env.UE_BUILD_TOOL_PATH;
12
22
  if (envPath)
13
23
  return envPath;
14
- const versions = ["5.8", "5.7", "5.6", "5.5", "5.4", "5.3"];
15
24
  const scriptName = IS_WINDOWS ? "Build.bat" : "Build.sh";
25
+ // Prefer the engine the project's EngineAssociation actually points at, so a
26
+ // 5.7 project builds with 5.7's Build tool - not whatever version happens to
27
+ // sort first in the fallback search below. The editor launch already respects
28
+ // the association (findEditorExecutable); without this the CLI build could
29
+ // silently compile against a different engine than the editor runs, masking
30
+ // API incompatibilities until the editor's own rebuild fails.
31
+ const associatedRoot = findEngineInstall(engineAssociation ?? null);
32
+ if (associatedRoot) {
33
+ const associatedTool = path.join(associatedRoot, "Engine", "Build", "BatchFiles", scriptName);
34
+ if (fs.existsSync(associatedTool))
35
+ return associatedTool;
36
+ }
37
+ const versions = ["5.8", "5.7", "5.6", "5.5", "5.4", "5.3"];
16
38
  const searchRoots = IS_WINDOWS
17
39
  ? [
18
40
  "C:/Program Files/Epic Games",
@@ -56,7 +78,7 @@ function findEditorExecutable(project) {
56
78
  return associatedEditorExe;
57
79
  }
58
80
  }
59
- const buildTool = findUEBuildTool();
81
+ const buildTool = findUEBuildTool(project?.engineAssociation ?? null);
60
82
  if (!buildTool)
61
83
  return null;
62
84
  const engineRoot = path.resolve(buildTool, "..", "..", "..", "..");
@@ -231,7 +253,8 @@ function getPlatformString() {
231
253
  return "Linux";
232
254
  }
233
255
  export async function buildProject(projectPath, opts = {}) {
234
- const buildTool = findUEBuildTool();
256
+ const resolvedPath = path.resolve(projectPath);
257
+ const buildTool = findUEBuildTool(readEngineAssociation(resolvedPath));
235
258
  if (!buildTool) {
236
259
  return {
237
260
  success: false,
@@ -239,7 +262,6 @@ export async function buildProject(projectPath, opts = {}) {
239
262
  message: "Unreal Engine build tool not found. Set UE_BUILD_TOOL_PATH or install UE5.3+ to a default location.",
240
263
  };
241
264
  }
242
- const resolvedPath = path.resolve(projectPath);
243
265
  if (!fs.existsSync(resolvedPath)) {
244
266
  return { success: false, exitCode: null, message: `Project file not found: ${resolvedPath}` };
245
267
  }
@@ -1 +1 @@
1
- {"version":3,"file":"editor-control.js","sourceRoot":"","sources":["../src/editor-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAE3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAEhD,MAAM,gBAAgB,GACpB,2JAA2J,CAAC;AAE9J,SAAS,eAAe;IACtB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC/C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC;IAEzD,MAAM,WAAW,GAAa,UAAU;QACtC,CAAC,CAAC;YACE,6BAA6B;YAC7B,6BAA6B;YAC7B,6BAA6B;YAC7B,eAAe;YACf,eAAe;YACf,eAAe;SAChB;QACH,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAC7B,CAAC,CAAC,CAAC,0BAA0B,CAAC;YAC9B,CAAC,CAAC;gBACE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE,cAAc,CAAC;gBACtD,mBAAmB;aACpB,CAAC;IAER,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;YACxG,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;gBACjC,OAAO,aAAa,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,2FAA2F;IAC3F,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACjG,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,WAAW,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAwB;IACpD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC3C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,IAAI,IAAI,CAAC,CAAC;IACnF,IAAI,oBAAoB,EAAE,CAAC;QACzB,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;QAC/G,IAAI,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACvC,OAAO,mBAAmB,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;IACpC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;IAE3F,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,CAAC;QACH,0EAA0E;QAC1E,MAAM,MAAM,GAAG,QAAQ,CAAC,kDAAkD,EAAE;YAC1E,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,sFAAsF;QACtF,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,GAAG,IAAI;IAC3G,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,cAAc,GAAG,GAAG,EAAE,eAAe,GAAG,IAAI;IACvE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,cAAc,GAAG,IAAI,CAAC;IAExC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;QAC1C,IAAI,MAAM,iBAAiB,EAAE,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAuB;IACvD,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IACtE,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,oHAAoH;SAC9H,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,6DAA6D,EAAE,CAAC;IACpG,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;YAC5D,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,aAAa,CAAC,KAAK,EAAE,CAAC;QAEtB,6DAA6D;QAC7D,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,0GAA0G;aACpH,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,yCAAyC,SAAS,EAAE,EAAE,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAC9F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAK,GAAG,KAAK;IAC5C,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IACtE,MAAM,cAAc,GAAG,eAAe,EAAE,CAAC;IACzC,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAE3C,IAAI,CAAC,cAAc,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,CAAC;YACV,QAAQ,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;QAC3D,CAAC;QAED,uDAAuD;QACvD,QAAQ,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAE7D,uDAAuD;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;gBACvB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC;YAClE,CAAC;QACH,CAAC;QAED,qCAAqC;QACrC,QAAQ,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAE1D,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,oDAAoD,EAAE,CAAC;QAC1F,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,gEAAgE;SAC1E,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,0BAA0B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAC5F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAuB,EAAE,MAA2D;IACtH,MAAM,UAAU,GAAG,MAAM,UAAU,EAAE,CAAC;IACtC,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC;QAC7C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;IACrF,CAAC;IAED,wDAAwD;IACxD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1D,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,mCAAmC;IACnC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAQD,SAAS,iBAAiB;IACxB,IAAI,UAAU;QAAE,OAAO,OAAO,CAAC;IAC/B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAmB,EACnB,OAA8C,EAAE;IAEhD,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;IACpC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,IAAI;YACd,OAAO,EACL,qGAAqG;SACxG,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,2BAA2B,YAAY,EAAE,EAAE,CAAC;IAChG,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,GAAG,WAAW,QAAQ,CAAC;IACtC,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IAErC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,YAAY,GAAG,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;IAEhH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,aAAa,GAAG,IAAI,SAAS,GAAG,CAAC;YACvC,MAAM,WAAW,GAAG,WAAW,aAAa,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACvE,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;;gBAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEjD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,OAAO,CACL,IAAI,KAAK,CAAC;gBACR,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE;gBAC5D,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,+BAA+B,IAAI,EAAE,EAAE,CACvF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"editor-control.js","sourceRoot":"","sources":["../src/editor-control.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -11,7 +11,10 @@ export declare enum ErrorCode {
11
11
  NO_HANDLER = "NO_HANDLER",
12
12
  PROJECT_NOT_LOADED = "PROJECT_NOT_LOADED",
13
13
  NOT_FOUND = "NOT_FOUND",
14
- INVALID_PARAMS = "INVALID_PARAMS"
14
+ INVALID_PARAMS = "INVALID_PARAMS",
15
+ /** A source-control guard refused a mutating bridge call before it ran
16
+ * (e.g. the target is checked out by another user, or checkout failed). */
17
+ WRITE_BLOCKED = "WRITE_BLOCKED"
15
18
  }
16
19
  export declare class McpError extends Error {
17
20
  readonly code: ErrorCode;
package/dist/errors.js CHANGED
@@ -13,6 +13,9 @@ export var ErrorCode;
13
13
  ErrorCode["PROJECT_NOT_LOADED"] = "PROJECT_NOT_LOADED";
14
14
  ErrorCode["NOT_FOUND"] = "NOT_FOUND";
15
15
  ErrorCode["INVALID_PARAMS"] = "INVALID_PARAMS";
16
+ /** A source-control guard refused a mutating bridge call before it ran
17
+ * (e.g. the target is checked out by another user, or checkout failed). */
18
+ ErrorCode["WRITE_BLOCKED"] = "WRITE_BLOCKED";
16
19
  })(ErrorCode || (ErrorCode = {}));
17
20
  export class McpError extends Error {
18
21
  code;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,SAUX;AAVD,WAAY,SAAS;IACnB,4CAA+B,CAAA;IAC/B,8CAAiC,CAAA;IACjC,0CAA6B,CAAA;IAC7B,gDAAmC,CAAA;IACnC,8CAAiC,CAAA;IACjC,sCAAyB,CAAA;IACzB,sDAAyC,CAAA;IACzC,oCAAuB,CAAA;IACvB,8CAAiC,CAAA;AACnC,CAAC,EAVW,SAAS,KAAT,SAAS,QAUpB;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IADlB,YACkB,IAAe,EAC/B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAW;QAI/B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,SAaX;AAbD,WAAY,SAAS;IACnB,4CAA+B,CAAA;IAC/B,8CAAiC,CAAA;IACjC,0CAA6B,CAAA;IAC7B,gDAAmC,CAAA;IACnC,8CAAiC,CAAA;IACjC,sCAAyB,CAAA;IACzB,sDAAyC,CAAA;IACzC,oCAAuB,CAAA;IACvB,8CAAiC,CAAA;IACjC;gFAC4E;IAC5E,4CAA+B,CAAA;AACjC,CAAC,EAbW,SAAS,KAAT,SAAS,QAapB;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IADlB,YACkB,IAAe,EAC/B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAW;QAI/B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,60 @@
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.
4
+ *
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.
11
+ *
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.
16
+ */
17
+ import type { IBridge } from "../bridge.js";
18
+ import { type WriteClassification } from "./write-methods.js";
19
+ /** Resolve a UE content path to an absolute on-disk file, or null if it does not exist. */
20
+ export type ResolveExistingFile = (contentPath: string) => string | null;
21
+ /** Per-call execution context passed to every guard. Analogous to a NestJS ExecutionContext. */
22
+ export interface CallContext {
23
+ readonly method: string;
24
+ readonly params: Record<string, unknown>;
25
+ readonly timeoutMs?: number;
26
+ /** The RAW bridge (never the guarded wrapper) for guards that must query the editor. */
27
+ readonly bridge: IBridge;
28
+ /** Scratch space shared across guards for the life of one call. */
29
+ readonly meta: Map<string, unknown>;
30
+ /** Lazy: how this call classifies as a write (which content paths it touches). Cached. */
31
+ write(): WriteClassification;
32
+ /** Lazy: absolute, existing on-disk files this call will modify (subset of write paths). Cached. */
33
+ writeFiles(): string[];
34
+ }
35
+ /**
36
+ * A guard on the bridge pipeline. Any of the hooks is optional. Guards are
37
+ * agnostic: source control, access policy, audit, rate limiting, and approval
38
+ * gating are all just guards.
39
+ */
40
+ export interface BridgeGuard {
41
+ /** Stable identifier, for logging and ordering ties. */
42
+ readonly name: string;
43
+ /** Lower runs first in `before` and last in `after`. Default 0. */
44
+ readonly order?: number;
45
+ /** Whether this guard participates for a given call. Default: always. */
46
+ appliesTo?(ctx: CallContext): boolean | Promise<boolean>;
47
+ /** Runs before the call. Throw to DENY the call; side effects are allowed. */
48
+ before?(ctx: CallContext): Promise<void>;
49
+ /** Runs after a successful call. Return a value to replace the result; return nothing to leave it. */
50
+ after?(ctx: CallContext, result: unknown): Promise<unknown | void>;
51
+ }
52
+ /** An ordered set of guards. Built-in guards register directly; plugin guards are discovered. */
53
+ export declare class GuardRegistry {
54
+ private guards;
55
+ register(guard: BridgeGuard): this;
56
+ list(): readonly BridgeGuard[];
57
+ get size(): number;
58
+ }
59
+ /** Build the per-call context, wiring the lazy write-enrichment helpers. */
60
+ export declare function makeCallContext(method: string, params: Record<string, unknown>, timeoutMs: number | undefined, rawBridge: IBridge, resolveExistingFile: ResolveExistingFile): CallContext;
@@ -0,0 +1,34 @@
1
+ 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
+ }
17
+ }
18
+ /** Build the per-call context, wiring the lazy write-enrichment helpers. */
19
+ export function makeCallContext(method, params, timeoutMs, rawBridge, resolveExistingFile) {
20
+ let writeCache;
21
+ let filesCache;
22
+ const write = () => (writeCache ??= classifyWrite(method, params));
23
+ const writeFiles = () => {
24
+ if (filesCache)
25
+ return filesCache;
26
+ const c = write();
27
+ filesCache = c.writes
28
+ ? c.contentPaths.map(resolveExistingFile).filter((f) => f !== null)
29
+ : [];
30
+ return filesCache;
31
+ };
32
+ return { method, params, timeoutMs, bridge: rawBridge, meta: new Map(), write, writeFiles };
33
+ }
34
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/flow/guard.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,aAAa,EAA4B,MAAM,oBAAoB,CAAC;AAsC7E,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;IAExC,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,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,22 @@
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
+ import type { IBridge } from "../bridge.js";
12
+ import { GuardRegistry, type ResolveExistingFile } from "./guard.js";
13
+ export type { ResolveExistingFile } from "./guard.js";
14
+ export declare class GuardedBridge implements IBridge {
15
+ private readonly inner;
16
+ private readonly registry;
17
+ private readonly resolveExistingFile;
18
+ constructor(inner: IBridge, registry: GuardRegistry, resolveExistingFile: ResolveExistingFile);
19
+ get isConnected(): boolean;
20
+ connect(timeoutMs?: number): Promise<void>;
21
+ call(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
22
+ }
@@ -0,0 +1,46 @@
1
+ import { makeCallContext, } from "./guard.js";
2
+ export class GuardedBridge {
3
+ inner;
4
+ registry;
5
+ resolveExistingFile;
6
+ constructor(inner, registry, resolveExistingFile) {
7
+ this.inner = inner;
8
+ this.registry = registry;
9
+ this.resolveExistingFile = resolveExistingFile;
10
+ }
11
+ get isConnected() {
12
+ return this.inner.isConnected;
13
+ }
14
+ connect(timeoutMs) {
15
+ return this.inner.connect(timeoutMs);
16
+ }
17
+ async call(method, params, timeoutMs) {
18
+ if (this.registry.size === 0) {
19
+ return this.inner.call(method, params, timeoutMs);
20
+ }
21
+ const ctx = makeCallContext(method, params ?? {}, timeoutMs, this.inner, this.resolveExistingFile);
22
+ // Resolve applicability once so `before`/`after` see a consistent set.
23
+ const applicable = [];
24
+ for (const g of this.registry.list()) {
25
+ if (!g.appliesTo || (await g.appliesTo(ctx)))
26
+ applicable.push(g);
27
+ }
28
+ // before: in order. A throw denies the call and propagates unchanged.
29
+ for (const g of applicable) {
30
+ if (g.before)
31
+ await g.before(ctx);
32
+ }
33
+ let result = await this.inner.call(method, params, timeoutMs);
34
+ // after: in reverse order. A returned value replaces the result.
35
+ for (let i = applicable.length - 1; i >= 0; i--) {
36
+ const g = applicable[i];
37
+ if (g.after) {
38
+ const replaced = await g.after(ctx, result);
39
+ if (replaced !== undefined)
40
+ result = replaced;
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ }
46
+ //# sourceMappingURL=guarded-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guarded-bridge.js","sourceRoot":"","sources":["../../src/flow/guarded-bridge.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,eAAe,GAGhB,MAAM,YAAY,CAAC;AAIpB,MAAM,OAAO,aAAa;IAEL;IACA;IACA;IAHnB,YACmB,KAAc,EACd,QAAuB,EACvB,mBAAwC;QAFxC,UAAK,GAAL,KAAK,CAAS;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,wBAAmB,GAAnB,mBAAmB,CAAqB;IACxD,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,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,CAAC,CAAC;QAEnG,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"}
@@ -0,0 +1,13 @@
1
+ import type { TaskRegistry } from "@db-lyon/flowkit";
2
+ import type { IBridge } from "../bridge.js";
3
+ import type { ProjectContext } from "../project.js";
4
+ import type { ToolContext } from "../types.js";
5
+ import type { BridgeGuard, ResolveExistingFile } from "./guard.js";
6
+ /** Resolve a UE content path to an absolute file, or null if it does not exist. */
7
+ export declare function makeResolveExistingFile(project: ProjectContext): ResolveExistingFile;
8
+ /**
9
+ * Build a `BridgeGuard` for every `guard.<name>.<phase>` task in the registry.
10
+ * `rawBridge` (not the guarded wrapper) backs each guard task's context, so a
11
+ * guard that itself calls the bridge cannot recurse through the pipeline.
12
+ */
13
+ export declare function discoverTaskGuards(registry: TaskRegistry, ctx: ToolContext, rawBridge: IBridge): BridgeGuard[];
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Plugin-supplied guards, discovered from the task registry.
3
+ *
4
+ * A plugin registers a guard by declaring a task whose name matches
5
+ * `guard.<name>.<phase>`, where phase is one of:
6
+ * - `before` run before every call; throw / fail to DENY it
7
+ * - `beforeWrite` run before a call only when it resolves to existing on-disk
8
+ * files it will modify (the source-control checkout case)
9
+ * - `after` run after every successful call (audit, side effects)
10
+ * - `afterWrite` run after a write-classified call
11
+ *
12
+ * No new plugin-activation concept is needed: the loader already registers every
13
+ * `manifest.tasks` entry by name, so a `guard.*.*` task is picked up here. Each
14
+ * matched task becomes one `BridgeGuard`. The core knows nothing about what a
15
+ * guard does - source control, access policy, audit, and rate limiting are all
16
+ * just guards.
17
+ *
18
+ * A guard task is invoked with `{ method, params, paths }` (paths = the existing
19
+ * on-disk files the call will touch, empty for non-writes) plus, for `after`
20
+ * guards, `result`. A `before` guard denies the call by returning `success:false`
21
+ * or throwing.
22
+ */
23
+ import * as fs from "node:fs";
24
+ import { McpError, ErrorCode } from "../errors.js";
25
+ import { debug } from "../log.js";
26
+ const GUARD_TASK_RE = /^guard\.(.+)\.(before|beforeWrite|after|afterWrite)$/;
27
+ /** Resolve a UE content path to an absolute file, or null if it does not exist. */
28
+ export function makeResolveExistingFile(project) {
29
+ return (contentPath) => {
30
+ try {
31
+ const abs = project.resolveContentPath(contentPath);
32
+ return fs.existsSync(abs) ? abs : null;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ };
38
+ }
39
+ /**
40
+ * Build a `BridgeGuard` for every `guard.<name>.<phase>` task in the registry.
41
+ * `rawBridge` (not the guarded wrapper) backs each guard task's context, so a
42
+ * guard that itself calls the bridge cannot recurse through the pipeline.
43
+ */
44
+ export function discoverTaskGuards(registry, ctx, rawBridge) {
45
+ const guards = [];
46
+ for (const taskName of registry.listRegistered()) {
47
+ const m = GUARD_TASK_RE.exec(taskName);
48
+ if (!m)
49
+ continue;
50
+ const [, name, phase] = m;
51
+ const writeScoped = phase.endsWith("Write");
52
+ const isBefore = phase.startsWith("before");
53
+ const runTask = async (cc, result) => {
54
+ const guardCtx = { ...ctx, bridge: rawBridge };
55
+ const options = {
56
+ method: cc.method,
57
+ params: cc.params,
58
+ paths: cc.writeFiles(),
59
+ };
60
+ if (result !== undefined)
61
+ options.result = result;
62
+ try {
63
+ const task = await registry.create(taskName, guardCtx, options);
64
+ return await task.run();
65
+ }
66
+ catch (e) {
67
+ throw new McpError(ErrorCode.WRITE_BLOCKED, `guard '${name}' errored on ${cc.method}: ${e.message}`);
68
+ }
69
+ };
70
+ const guard = {
71
+ name: `${name}.${phase}`,
72
+ appliesTo: writeScoped ? (cc) => cc.writeFiles().length > 0 : undefined,
73
+ };
74
+ if (isBefore) {
75
+ guard.before = async (cc) => {
76
+ const r = await runTask(cc);
77
+ if (!r.success) {
78
+ const reason = r.error?.message ?? `denied by guard '${name}'`;
79
+ const scope = cc.writeFiles().length ? ` on ${cc.writeFiles().join(", ")}` : "";
80
+ throw new McpError(ErrorCode.WRITE_BLOCKED, `blocked (${cc.method})${scope}: ${reason}`);
81
+ }
82
+ debug("guard", `guard '${name}' allowed ${cc.method}`);
83
+ };
84
+ }
85
+ else {
86
+ // `after` guards observe the result for side effects (audit); a failing
87
+ // after-guard is logged but does not fail the already-completed call.
88
+ guard.after = async (cc, result) => {
89
+ const r = await runTask(cc, result);
90
+ if (!r.success)
91
+ debug("guard", `after-guard '${name}' reported failure on ${cc.method}: ${r.error?.message}`);
92
+ };
93
+ }
94
+ guards.push(guard);
95
+ }
96
+ return guards;
97
+ }
98
+ //# sourceMappingURL=task-guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-guards.js","sourceRoot":"","sources":["../../src/flow/task-guards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Write classification for the source-control guard.
3
+ *
4
+ * The guard needs to know, for a given bridge method + params, which asset
5
+ * content paths the call is about to modify, so it can check them out (or refuse
6
+ * on a human's lock) BEFORE the write reaches disk. This module is the single
7
+ * place that encodes that knowledge.
8
+ *
9
+ * Two layers:
10
+ * 1. An explicit map for methods whose path lives under an unusual param
11
+ * shape (batches, rename descriptors).
12
+ * 2. A verb+param heuristic for the common case: a method named with a write
13
+ * verb (`save_`, `set_`, ...) carrying a recognizable asset-path param.
14
+ *
15
+ * Classification returns UE content paths (e.g. "/Game/Foo"). Resolving those to
16
+ * on-disk files, and deciding which already exist (modify -> checkout) versus do
17
+ * not (create -> skip, it will be `p4 add`ed later), is the caller's job.
18
+ *
19
+ * Design note: this is intentionally conservative. An unmapped write falls
20
+ * through as "not a write" (fail-open). The cost of a miss is that the agent
21
+ * hits Unreal's own read-only failure and can check out explicitly - visible,
22
+ * not silent corruption. The cost of a false positive is an unnecessary
23
+ * checkout, which takes a lock. We bias toward not over-locking.
24
+ */
25
+ export interface WriteClassification {
26
+ writes: boolean;
27
+ /** UE content paths the call modifies. Empty when nothing is guardable. */
28
+ contentPaths: string[];
29
+ }
30
+ /**
31
+ * Classify a bridge call. Returns the content paths a mutation will touch, or
32
+ * `writes: false` when the call is not a guardable write.
33
+ */
34
+ export declare function classifyWrite(method: string, params: Record<string, unknown>): WriteClassification;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Write classification for the source-control guard.
3
+ *
4
+ * The guard needs to know, for a given bridge method + params, which asset
5
+ * content paths the call is about to modify, so it can check them out (or refuse
6
+ * on a human's lock) BEFORE the write reaches disk. This module is the single
7
+ * place that encodes that knowledge.
8
+ *
9
+ * Two layers:
10
+ * 1. An explicit map for methods whose path lives under an unusual param
11
+ * shape (batches, rename descriptors).
12
+ * 2. A verb+param heuristic for the common case: a method named with a write
13
+ * verb (`save_`, `set_`, ...) carrying a recognizable asset-path param.
14
+ *
15
+ * Classification returns UE content paths (e.g. "/Game/Foo"). Resolving those to
16
+ * on-disk files, and deciding which already exist (modify -> checkout) versus do
17
+ * not (create -> skip, it will be `p4 add`ed later), is the caller's job.
18
+ *
19
+ * Design note: this is intentionally conservative. An unmapped write falls
20
+ * through as "not a write" (fail-open). The cost of a miss is that the agent
21
+ * hits Unreal's own read-only failure and can check out explicitly - visible,
22
+ * not silent corruption. The cost of a false positive is an unnecessary
23
+ * checkout, which takes a lock. We bias toward not over-locking.
24
+ */
25
+ /** Method-name prefixes that denote a mutation. Read verbs are excluded. */
26
+ const WRITE_VERB = /^(save|set|create|add|delete|remove|import|rename|move|duplicate|reparent|compile|apply|assign|modify|bake|generate|build)_/;
27
+ /** Single-value params that carry an asset content path. */
28
+ const PATH_KEYS = ["assetPath", "sourcePath", "destinationPath", "packagePath", "path"];
29
+ /** Array params that carry asset content paths. */
30
+ const PATH_ARRAY_KEYS = ["assetPaths", "sourcePaths", "destinationPaths"];
31
+ /** Coerce a param to a non-empty string, or null. */
32
+ function str(v) {
33
+ return typeof v === "string" && v.length > 0 ? v : null;
34
+ }
35
+ /** Coerce a param to an array of non-empty strings. */
36
+ function strArray(v) {
37
+ return Array.isArray(v) ? v.filter((x) => typeof x === "string" && x.length > 0) : [];
38
+ }
39
+ /**
40
+ * Explicit extractors for methods whose target path is not a plain PATH_KEYS
41
+ * lookup. Keyed by bare bridge method name.
42
+ */
43
+ const EXPLICIT = {
44
+ // Batch rename: each entry is {sourcePath, destinationPath} or {assetPath, newName}.
45
+ bulk_rename_assets: (p) => {
46
+ const out = [];
47
+ for (const r of (Array.isArray(p.renames) ? p.renames : [])) {
48
+ const s = str(r.sourcePath) ?? str(r.assetPath);
49
+ if (s)
50
+ out.push(s);
51
+ }
52
+ return out;
53
+ },
54
+ // Batch delete.
55
+ delete_asset_batch: (p) => strArray(p.assetPaths),
56
+ };
57
+ /**
58
+ * Classify a bridge call. Returns the content paths a mutation will touch, or
59
+ * `writes: false` when the call is not a guardable write.
60
+ */
61
+ export function classifyWrite(method, params) {
62
+ const explicit = EXPLICIT[method];
63
+ if (explicit) {
64
+ const contentPaths = dedupe(explicit(params));
65
+ return { writes: contentPaths.length > 0, contentPaths };
66
+ }
67
+ if (!WRITE_VERB.test(method)) {
68
+ return { writes: false, contentPaths: [] };
69
+ }
70
+ const contentPaths = [];
71
+ for (const key of PATH_KEYS) {
72
+ const v = str(params[key]);
73
+ if (v)
74
+ contentPaths.push(v);
75
+ }
76
+ for (const key of PATH_ARRAY_KEYS) {
77
+ contentPaths.push(...strArray(params[key]));
78
+ }
79
+ const deduped = dedupe(contentPaths);
80
+ return { writes: deduped.length > 0, contentPaths: deduped };
81
+ }
82
+ function dedupe(xs) {
83
+ return [...new Set(xs)];
84
+ }
85
+ //# sourceMappingURL=write-methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-methods.js","sourceRoot":"","sources":["../../src/flow/write-methods.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -10,6 +10,9 @@ import { McpError, ErrorCode } from "./errors.js";
10
10
  import { info, warn } from "./log.js";
11
11
  import { startVersionCheck, consumeUpgradeNotice } from "./version-check.js";
12
12
  import { buildFlowRegistry } from "./flow/registry.js";
13
+ import { GuardRegistry } from "./flow/guard.js";
14
+ import { GuardedBridge } from "./flow/guarded-bridge.js";
15
+ import { makeResolveExistingFile, discoverTaskGuards } from "./flow/task-guards.js";
13
16
  import { loadFlowConfig } from "./flow/loader.js";
14
17
  import { createFlowTool } from "./flow/flow-tool.js";
15
18
  import { startFlowHttpServer } from "./flow/http-server.js";
@@ -185,7 +188,13 @@ async function main() {
185
188
  return result;
186
189
  };
187
190
  };
188
- const ctx = { bridge, project, getFlows, getPlugins };
191
+ // Wrap the raw bridge in the guard pipeline. The raw `bridge` stays in scope
192
+ // for connection lifecycle (connect / reconnect / lockfile); the guarded
193
+ // wrapper is what tools and tasks see. The registry starts empty (pass-through)
194
+ // and is populated once the task registry exists, below.
195
+ const guardRegistry = new GuardRegistry();
196
+ const guardedBridge = new GuardedBridge(bridge, guardRegistry, makeResolveExistingFile(project));
197
+ const ctx = { bridge: guardedBridge, project, getFlows, getPlugins };
189
198
  // ── Flow engine: task registry ──────────────────────────────────
190
199
  const registry = buildFlowRegistry(registryTools);
191
200
  for (const { name, ctor } of pluginLoad.taskRegistrations) {
@@ -195,6 +204,15 @@ async function main() {
195
204
  registry.registerClassPath(classPath, ctor);
196
205
  }
197
206
  const taskCount = registry.listRegistered().length;
207
+ // Populate the guard pipeline: any plugin-supplied `guard.<name>.<phase>` task
208
+ // becomes a BridgeGuard. Each guard task runs with the RAW bridge in its
209
+ // context so a guard cannot recurse through the pipeline. See flow/task-guards.ts.
210
+ for (const g of discoverTaskGuards(registry, ctx, bridge)) {
211
+ guardRegistry.register(g);
212
+ }
213
+ if (guardRegistry.size > 0) {
214
+ info("guard", `${guardRegistry.size} bridge guard(s) active: ${guardRegistry.list().map((g) => g.name).join(", ")}`);
215
+ }
198
216
  // ── Plugin knowledge → server instructions ──────────────────────
199
217
  // Attach per-category markdown to the AI-facing docs. Sized to the same
200
218
  // budget as SERVER_INSTRUCTIONS itself; deeper plugin docs remain
@@ -226,7 +244,7 @@ async function main() {
226
244
  const action = params.action;
227
245
  const taskName = `${tool.name}.${action}`;
228
246
  const { action: _, ...taskParams } = params;
229
- const flowCtx = { bridge, project, getFlows, getPlugins, elicit: ctx.elicit };
247
+ const flowCtx = { bridge: guardedBridge, project, getFlows, getPlugins, elicit: ctx.elicit };
230
248
  try {
231
249
  const task = await registry.create(taskName, flowCtx, taskParams);
232
250
  const result = await task.run();