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.
- package/README.md +1 -1
- package/dist/editor-control.js +27 -5
- package/dist/editor-control.js.map +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/flow/guard.d.ts +60 -0
- package/dist/flow/guard.js +34 -0
- package/dist/flow/guard.js.map +1 -0
- package/dist/flow/guarded-bridge.d.ts +22 -0
- package/dist/flow/guarded-bridge.js +46 -0
- package/dist/flow/guarded-bridge.js.map +1 -0
- package/dist/flow/task-guards.d.ts +13 -0
- package/dist/flow/task-guards.js +98 -0
- package/dist/flow/task-guards.js.map +1 -0
- package/dist/flow/write-methods.d.ts +34 -0
- package/dist/flow/write-methods.js +85 -0
- package/dist/flow/write-methods.js.map +1 -0
- package/dist/index.js +20 -2
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +3 -3
- package/dist/instructions.js +4 -4
- package/dist/lean-context.d.ts +2 -2
- package/dist/lean-context.js +1 -1
- package/dist/tool-counts.json +7 -6
- package/dist/tools/fab.d.ts +2 -0
- package/dist/tools/fab.js +29 -0
- package/dist/tools/fab.js.map +1 -0
- package/dist/tools.js +2 -0
- package/dist/tools.js.map +1 -1
- package/package.json +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_MotionMatching.cpp +6 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +7 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +3 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers.cpp +24 -6
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FabHandlers.cpp +244 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FabHandlers.h +33 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +15 -0
- 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 -->
|
|
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
|
package/dist/editor-control.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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":"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"}
|
|
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;
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAO9B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,MAAM,aAAa,GAAG,sDAAsD,CAAC;AAE7E,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,OAAO,CAAC,WAAmB,EAAiB,EAAE;QAC5C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;YACpD,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAsB,EACtB,GAAgB,EAChB,SAAkB;IAElB,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE5C,MAAM,OAAO,GAAG,KAAK,EAAE,EAAe,EAAE,MAAgB,EAAE,EAAE;YAC1D,MAAM,QAAQ,GAAgB,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC5D,MAAM,OAAO,GAA4B;gBACvC,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,KAAK,EAAE,EAAE,CAAC,UAAU,EAAE;aACvB,CAAC;YACF,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChE,OAAO,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,UAAU,IAAI,gBAAgB,EAAE,CAAC,MAAM,KAAM,CAAW,CAAC,OAAO,EAAE,CACnE,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,KAAK,GAAgB;YACzB,IAAI,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;YACxB,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;SACxE,CAAC;QAEF,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,EAAE,EAAE,EAAE;gBAC1B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;oBACf,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,oBAAoB,IAAI,GAAG,CAAC;oBAC/D,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAChF,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,YAAY,EAAE,CAAC,MAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC;gBAC3F,CAAC;gBACD,KAAK,CAAC,OAAO,EAAE,UAAU,IAAI,aAAa,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YACzD,CAAC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,wEAAwE;YACxE,sEAAsE;YACtE,KAAK,CAAC,KAAK,GAAG,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE;gBACjC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBACpC,IAAI,CAAC,CAAC,CAAC,OAAO;oBAAE,KAAK,CAAC,OAAO,EAAE,gBAAgB,IAAI,yBAAyB,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YAChH,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -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
|
-
|
|
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();
|