flockbay 0.10.15
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 +56 -0
- package/bin/flockbay-mcp.mjs +56 -0
- package/bin/flockbay.mjs +78 -0
- package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
- package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
- package/dist/index--o4BPz5o.cjs +10311 -0
- package/dist/index-CUp3juDS.mjs +10268 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +40 -0
- package/dist/lib.cjs +33 -0
- package/dist/lib.d.cts +957 -0
- package/dist/lib.d.mts +957 -0
- package/dist/lib.mjs +23 -0
- package/dist/runCodex-D3eT-TvB.cjs +3449 -0
- package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
- package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
- package/dist/runGemini-CBxZp6I7.cjs +3185 -0
- package/dist/types-C-jnUdn_.cjs +4498 -0
- package/dist/types-DGd6ea2Z.mjs +4450 -0
- package/kits/kit.open_world/kit.json +59 -0
- package/package.json +130 -0
- package/scripts/claude_local_launcher.cjs +73 -0
- package/scripts/claude_remote_launcher.cjs +16 -0
- package/scripts/claude_version_utils.cjs +391 -0
- package/scripts/ripgrep_launcher.cjs +33 -0
- package/scripts/session_hook_forwarder.cjs +49 -0
- package/scripts/test-codex-abort-history.mjs +77 -0
- package/scripts/unpack-tools.cjs +222 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
- package/tools/unreal-mcp/upstream/Python/README.md +40 -0
- package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
- package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
- package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
- package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
- package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
- package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
- package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
- package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
- package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Flockbay CLI
|
|
2
|
+
|
|
3
|
+
Code on the go controlling Claude/Codex sessions from your mobile device.
|
|
4
|
+
|
|
5
|
+
Code anywhere.
|
|
6
|
+
|
|
7
|
+
Flockbay CLI is the command-line tool for running and controlling Flockbay sessions (including daemon and Codex mode).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g flockbay
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
flockbay
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This will:
|
|
22
|
+
1. Start a Claude Code session
|
|
23
|
+
2. Display a QR code to connect from your mobile device
|
|
24
|
+
3. Allow real-time session sharing between Claude Code and your mobile app
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
- `flockbay auth` – Manage authentication
|
|
29
|
+
- `flockbay codex` – Start Codex mode
|
|
30
|
+
- `flockbay connect` – Store AI vendor API keys in Flockbay
|
|
31
|
+
- `flockbay notify` – Send a push notification to your devices
|
|
32
|
+
- `flockbay daemon` – Manage background service
|
|
33
|
+
- `flockbay doctor` – System diagnostics & troubleshooting
|
|
34
|
+
|
|
35
|
+
## Options
|
|
36
|
+
|
|
37
|
+
- `-h, --help` - Show help
|
|
38
|
+
- `-v, --version` - Show version
|
|
39
|
+
- `-m, --model <model>` - Claude model to use (default: sonnet)
|
|
40
|
+
- `-p, --permission-mode <mode>` - Permission mode: auto, default, or plan
|
|
41
|
+
- `--claude-env KEY=VALUE` - Set environment variable for Claude Code (e.g., for [claude-code-router](https://github.com/musistudio/claude-code-router))
|
|
42
|
+
- `--claude-arg ARG` - Pass additional argument to Claude CLI
|
|
43
|
+
|
|
44
|
+
Run `flockbay --help` for the complete list of options.
|
|
45
|
+
|
|
46
|
+
## Requirements
|
|
47
|
+
|
|
48
|
+
- Node.js >= 20.0.0
|
|
49
|
+
- Required by `eventsource-parser@3.0.5`, which is required by
|
|
50
|
+
`@modelcontextprotocol/sdk`, which we used to implement permission forwarding
|
|
51
|
+
to mobile app
|
|
52
|
+
- Claude CLI installed & logged in (`claude` command available in PATH)
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
Proprietary. Copyright (c) 2024-2026 Flockbay. All rights reserved.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
// Ensure Node flags to reduce noisy warnings on stdout (which could interfere with MCP).
|
|
9
|
+
const hasNoWarnings = process.execArgv.includes('--no-warnings');
|
|
10
|
+
const hasNoDeprecation = process.execArgv.includes('--no-deprecation');
|
|
11
|
+
|
|
12
|
+
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
13
|
+
const distEntrypoint = join(projectRoot, 'dist', 'codex', 'flockbayMcpStdioBridge.mjs');
|
|
14
|
+
const devEntrypoint = join(projectRoot, 'src', 'codex', 'flockbayMcpStdioBridge.ts');
|
|
15
|
+
const entrypoint = existsSync(distEntrypoint) ? distEntrypoint : devEntrypoint;
|
|
16
|
+
const useTsx = entrypoint.endsWith('.ts');
|
|
17
|
+
const invokedCwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
function resolveTsxImportArgs() {
|
|
20
|
+
if (!useTsx) return [];
|
|
21
|
+
const candidates = [
|
|
22
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'esm', 'index.mjs'),
|
|
23
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'esm', 'index.js'),
|
|
24
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.mjs'),
|
|
25
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.js'),
|
|
26
|
+
];
|
|
27
|
+
const resolved = candidates.find(existsSync);
|
|
28
|
+
return resolved ? ['--import', resolved] : ['--import', 'tsx'];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!hasNoWarnings || !hasNoDeprecation || useTsx) {
|
|
32
|
+
try {
|
|
33
|
+
execFileSync(
|
|
34
|
+
process.execPath,
|
|
35
|
+
[
|
|
36
|
+
'--no-warnings',
|
|
37
|
+
'--no-deprecation',
|
|
38
|
+
...resolveTsxImportArgs(),
|
|
39
|
+
entrypoint,
|
|
40
|
+
...process.argv.slice(2),
|
|
41
|
+
],
|
|
42
|
+
{
|
|
43
|
+
stdio: 'inherit',
|
|
44
|
+
...(useTsx ? { cwd: projectRoot } : {}),
|
|
45
|
+
env: {
|
|
46
|
+
...process.env,
|
|
47
|
+
...(useTsx ? { FLOCKBAY_INVOKED_CWD: invokedCwd } : {}),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
process.exit(error?.status || 1);
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
await import('../dist/codex/flockbayMcpStdioBridge.mjs');
|
|
56
|
+
}
|
package/bin/flockbay.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, statSync } from 'node:fs';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
// Ensure Node flags to reduce noisy warnings on stdout.
|
|
9
|
+
const hasNoWarnings = process.execArgv.includes('--no-warnings');
|
|
10
|
+
const hasNoDeprecation = process.execArgv.includes('--no-deprecation');
|
|
11
|
+
|
|
12
|
+
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
13
|
+
const distEntrypoint = join(projectRoot, 'dist', 'index.mjs');
|
|
14
|
+
const devEntrypoint = join(projectRoot, 'src', 'index.ts');
|
|
15
|
+
const entrypoint = (() => {
|
|
16
|
+
const forceSrc = process.env.FLOCKBAY_USE_SRC === '1';
|
|
17
|
+
const forceDist = process.env.FLOCKBAY_USE_DIST === '1';
|
|
18
|
+
|
|
19
|
+
const hasDist = existsSync(distEntrypoint);
|
|
20
|
+
const hasDev = existsSync(devEntrypoint);
|
|
21
|
+
|
|
22
|
+
if (forceSrc && hasDev) return devEntrypoint;
|
|
23
|
+
if (forceDist && hasDist) return distEntrypoint;
|
|
24
|
+
|
|
25
|
+
if (hasDist && hasDev) {
|
|
26
|
+
try {
|
|
27
|
+
const devTime = statSync(devEntrypoint).mtimeMs;
|
|
28
|
+
const distTime = statSync(distEntrypoint).mtimeMs;
|
|
29
|
+
if (devTime > distTime) return devEntrypoint;
|
|
30
|
+
} catch {
|
|
31
|
+
// ignore
|
|
32
|
+
}
|
|
33
|
+
return distEntrypoint;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return hasDist ? distEntrypoint : devEntrypoint;
|
|
37
|
+
})();
|
|
38
|
+
const useTsx = entrypoint.endsWith('.ts');
|
|
39
|
+
const invokedCwd = process.cwd();
|
|
40
|
+
|
|
41
|
+
function resolveTsxImportArgs() {
|
|
42
|
+
if (!useTsx) return [];
|
|
43
|
+
const candidates = [
|
|
44
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'esm', 'index.mjs'),
|
|
45
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'esm', 'index.js'),
|
|
46
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.mjs'),
|
|
47
|
+
join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.js'),
|
|
48
|
+
];
|
|
49
|
+
const resolved = candidates.find(existsSync);
|
|
50
|
+
return resolved ? ['--import', resolved] : ['--import', 'tsx'];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!hasNoWarnings || !hasNoDeprecation || useTsx) {
|
|
54
|
+
try {
|
|
55
|
+
execFileSync(
|
|
56
|
+
process.execPath,
|
|
57
|
+
[
|
|
58
|
+
'--no-warnings',
|
|
59
|
+
'--no-deprecation',
|
|
60
|
+
...resolveTsxImportArgs(),
|
|
61
|
+
entrypoint,
|
|
62
|
+
...process.argv.slice(2),
|
|
63
|
+
],
|
|
64
|
+
{
|
|
65
|
+
stdio: 'inherit',
|
|
66
|
+
...(useTsx ? { cwd: projectRoot } : {}),
|
|
67
|
+
env: {
|
|
68
|
+
...process.env,
|
|
69
|
+
...(useTsx ? { FLOCKBAY_INVOKED_CWD: invokedCwd } : {}),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
process.exit(error?.status || 1);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
await import('../dist/index.mjs');
|
|
78
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
4
|
+
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
5
|
+
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
6
|
+
var streamableHttp_js = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
7
|
+
var z = require('zod');
|
|
8
|
+
|
|
9
|
+
function getToolCallTimeoutMs(name, args) {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
let url = null;
|
|
14
|
+
for (let i = 0; i < argv.length; i++) {
|
|
15
|
+
const a = argv[i];
|
|
16
|
+
if (a === "--url" && i + 1 < argv.length) {
|
|
17
|
+
url = argv[i + 1];
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { url };
|
|
22
|
+
}
|
|
23
|
+
async function main() {
|
|
24
|
+
const { url: urlFromArgs } = parseArgs(process.argv.slice(2));
|
|
25
|
+
const baseUrl = urlFromArgs || process.env.FLOCKBAY_HTTP_MCP_URL || "";
|
|
26
|
+
if (!baseUrl) {
|
|
27
|
+
process.stderr.write(
|
|
28
|
+
"[flockbay-mcp] Missing target URL. Set FLOCKBAY_HTTP_MCP_URL or pass --url <http://127.0.0.1:PORT>\n"
|
|
29
|
+
);
|
|
30
|
+
process.exit(2);
|
|
31
|
+
}
|
|
32
|
+
let httpClient = null;
|
|
33
|
+
async function ensureHttpClient() {
|
|
34
|
+
if (httpClient) return httpClient;
|
|
35
|
+
const client = new index_js.Client(
|
|
36
|
+
{ name: "flockbay-stdio-bridge", version: "1.0.0" },
|
|
37
|
+
{ capabilities: {} }
|
|
38
|
+
);
|
|
39
|
+
const transport = new streamableHttp_js.StreamableHTTPClientTransport(new URL(baseUrl));
|
|
40
|
+
await client.connect(transport);
|
|
41
|
+
httpClient = client;
|
|
42
|
+
return client;
|
|
43
|
+
}
|
|
44
|
+
const server = new mcp_js.McpServer({
|
|
45
|
+
name: "Flockbay MCP Bridge",
|
|
46
|
+
version: "1.0.0"
|
|
47
|
+
});
|
|
48
|
+
function forwardTool(name, inputSchema, title, description) {
|
|
49
|
+
server.registerTool(
|
|
50
|
+
name,
|
|
51
|
+
{ title, description, inputSchema },
|
|
52
|
+
async (args) => {
|
|
53
|
+
try {
|
|
54
|
+
const client = await ensureHttpClient();
|
|
55
|
+
const timeout = getToolCallTimeoutMs(name, args);
|
|
56
|
+
const response = await client.callTool(
|
|
57
|
+
{ name, arguments: args },
|
|
58
|
+
void 0,
|
|
59
|
+
timeout ? { timeout } : void 0
|
|
60
|
+
);
|
|
61
|
+
return response;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{ type: "text", text: `Failed to call tool "${name}": ${error instanceof Error ? error.message : String(error)}` }
|
|
66
|
+
],
|
|
67
|
+
isError: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
forwardTool(
|
|
74
|
+
"change_title",
|
|
75
|
+
{ title: z.z.string().describe("The new title for the chat session") },
|
|
76
|
+
"Change Chat Title",
|
|
77
|
+
"Change the title of the current chat session"
|
|
78
|
+
);
|
|
79
|
+
forwardTool(
|
|
80
|
+
"latest_user_images",
|
|
81
|
+
{
|
|
82
|
+
limit: z.z.number().int().positive().optional().describe("Max number of images to return (default 4).")
|
|
83
|
+
},
|
|
84
|
+
"Latest User Images",
|
|
85
|
+
"Return the latest image attachments sent by the user (as image content blocks)."
|
|
86
|
+
);
|
|
87
|
+
forwardTool(
|
|
88
|
+
"read_images",
|
|
89
|
+
{
|
|
90
|
+
paths: z.z.array(z.z.string()).describe("Image paths (absolute or relative to the session directory). PNG only."),
|
|
91
|
+
limit: z.z.number().int().positive().optional().describe("Max number of images to include (default 10)."),
|
|
92
|
+
upload: z.z.boolean().optional().describe("Upload images to the session screenshots store and return HTTPS URLs (default true)."),
|
|
93
|
+
includeBase64: z.z.boolean().optional().describe("Include base64 data in the payload (default false)."),
|
|
94
|
+
maxBytesPerImage: z.z.number().int().positive().optional().describe("Max bytes per image when includeBase64=true (default 2500000).")
|
|
95
|
+
},
|
|
96
|
+
"Read Images",
|
|
97
|
+
"Read one or more local PNG images by path and return a `{ views: [...] }` payload for the UI."
|
|
98
|
+
);
|
|
99
|
+
forwardTool(
|
|
100
|
+
"ask_user_question",
|
|
101
|
+
{
|
|
102
|
+
questions: z.z.array(
|
|
103
|
+
z.z.object({
|
|
104
|
+
key: z.z.string().optional().describe("Stable key for this question (defaults to header)."),
|
|
105
|
+
header: z.z.string().describe("Short label for the question."),
|
|
106
|
+
question: z.z.string().describe("The question to show to the user."),
|
|
107
|
+
options: z.z.array(z.z.object({
|
|
108
|
+
label: z.z.string().describe("Option label"),
|
|
109
|
+
description: z.z.string().optional().describe("Optional short description")
|
|
110
|
+
})).min(1).describe("Available choices"),
|
|
111
|
+
multiSelect: z.z.boolean().optional().describe("Allow multiple selections")
|
|
112
|
+
})
|
|
113
|
+
).describe("Questions to ask the user")
|
|
114
|
+
},
|
|
115
|
+
"Ask User Question",
|
|
116
|
+
"Ask the user one or more multiple-choice questions and return structured answers."
|
|
117
|
+
);
|
|
118
|
+
forwardTool(
|
|
119
|
+
"coordination_ledger_snapshot",
|
|
120
|
+
{},
|
|
121
|
+
"Coordination Ledger Snapshot",
|
|
122
|
+
"Fetch the current coordination ledger snapshot (work items + intent) for this project."
|
|
123
|
+
);
|
|
124
|
+
forwardTool(
|
|
125
|
+
"ledger_read",
|
|
126
|
+
{},
|
|
127
|
+
"Ledger Read",
|
|
128
|
+
"Alias for coordination_ledger_snapshot: fetch the current shared coordination ledger snapshot for this project."
|
|
129
|
+
);
|
|
130
|
+
forwardTool(
|
|
131
|
+
"coordination_update_intent",
|
|
132
|
+
{
|
|
133
|
+
summary: z.z.string().optional().describe("Optional short summary/title for this work item."),
|
|
134
|
+
status: z.z.string().optional().describe("Optional work item status (e.g. wip, blocked)."),
|
|
135
|
+
plannedFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you plan to touch."),
|
|
136
|
+
activeFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you are actively editing right now."),
|
|
137
|
+
doneFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you are done with (safe for others to start)."),
|
|
138
|
+
waitingOnFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you are waiting on (owned/planned by others)."),
|
|
139
|
+
leaseMs: z.z.number().int().positive().optional().describe("Soft lease TTL for this ledger entry (ms). UI-only staleness hint; default ~2h.")
|
|
140
|
+
},
|
|
141
|
+
"Coordination Update Intent",
|
|
142
|
+
"Update this work item\u2019s coordination intent (planned/active/done/waiting). Communication-only (trust-first), not an enforced lock."
|
|
143
|
+
);
|
|
144
|
+
forwardTool(
|
|
145
|
+
"coordination_check_files",
|
|
146
|
+
{
|
|
147
|
+
files: z.z.array(z.z.string()).describe('Repo-relative file paths to check (e.g. "Config/DefaultGame.ini").'),
|
|
148
|
+
includeSelf: z.z.boolean().optional().describe("Include this work item in results (default true).")
|
|
149
|
+
},
|
|
150
|
+
"Coordination Check Files",
|
|
151
|
+
"Check which work items currently claim the given files (planned/active), ignoring stale/done entries."
|
|
152
|
+
);
|
|
153
|
+
forwardTool(
|
|
154
|
+
"coordination_claim_files",
|
|
155
|
+
{
|
|
156
|
+
files: z.z.array(z.z.string()).describe("Repo-relative file paths to claim."),
|
|
157
|
+
mode: z.z.enum(["planned", "active", "planned_and_active"]).optional().describe("How to claim: planned or active (default active)."),
|
|
158
|
+
leaseMs: z.z.number().int().positive().optional().describe("Soft lease TTL for this ledger entry (ms). Used to avoid stale blocks; default ~2h.")
|
|
159
|
+
},
|
|
160
|
+
"Coordination Claim Files",
|
|
161
|
+
"Atomically claim files for this work item if they are not currently owned by another active work item."
|
|
162
|
+
);
|
|
163
|
+
forwardTool(
|
|
164
|
+
"ledger_claim",
|
|
165
|
+
{
|
|
166
|
+
summary: z.z.string().optional().describe("Optional short summary/title for this work item."),
|
|
167
|
+
status: z.z.string().optional().describe("Optional work item status (e.g. wip, blocked)."),
|
|
168
|
+
plannedFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you plan to touch."),
|
|
169
|
+
files: z.z.array(z.z.string()).describe("Repo-relative file paths to claim."),
|
|
170
|
+
mode: z.z.enum(["planned", "active", "planned_and_active"]).optional().describe("How to claim: planned or active (default active)."),
|
|
171
|
+
leaseMs: z.z.number().int().positive().optional().describe("Soft lease TTL for this ledger entry (ms). Used to avoid stale blocks; default ~2h.")
|
|
172
|
+
},
|
|
173
|
+
"Ledger Claim",
|
|
174
|
+
"Alias for intent+claim: updates intent (optional) then atomically claims files for this work item."
|
|
175
|
+
);
|
|
176
|
+
forwardTool(
|
|
177
|
+
"ledger_release",
|
|
178
|
+
{
|
|
179
|
+
status: z.z.string().optional().describe('Status to set (default "done").'),
|
|
180
|
+
doneFiles: z.z.array(z.z.string()).optional().describe("Repo-relative file paths you finished (will be unioned with existing doneFiles)."),
|
|
181
|
+
clearActive: z.z.boolean().optional().describe("If true, clears activeFiles (default true)."),
|
|
182
|
+
clearPlanned: z.z.boolean().optional().describe("If true, clears plannedFiles too (default false)."),
|
|
183
|
+
commitHash: z.z.string().optional().describe("Optional commit hash to record on the work item.")
|
|
184
|
+
},
|
|
185
|
+
"Ledger Release",
|
|
186
|
+
"Mark work item complete/released: union doneFiles, clear active (and optionally planned), and set status (default done)."
|
|
187
|
+
);
|
|
188
|
+
forwardTool(
|
|
189
|
+
"docs_index_read",
|
|
190
|
+
{},
|
|
191
|
+
"Docs Index Read",
|
|
192
|
+
"Read the required game Documentation index (index.md) and a compact tree summary."
|
|
193
|
+
);
|
|
194
|
+
forwardTool(
|
|
195
|
+
"docs_tree",
|
|
196
|
+
{},
|
|
197
|
+
"Docs Tree",
|
|
198
|
+
"Fetch the Documentation Library tree (folders + docs metadata; no bodies)."
|
|
199
|
+
);
|
|
200
|
+
forwardTool(
|
|
201
|
+
"docs_get",
|
|
202
|
+
{
|
|
203
|
+
nodeId: z.z.string().describe("Document node id.")
|
|
204
|
+
},
|
|
205
|
+
"Docs Get",
|
|
206
|
+
"Fetch a single Documentation document node (includes markdown body)."
|
|
207
|
+
);
|
|
208
|
+
forwardTool(
|
|
209
|
+
"docs_search",
|
|
210
|
+
{
|
|
211
|
+
q: z.z.string().describe("Search query."),
|
|
212
|
+
limit: z.z.number().int().positive().optional().describe("Max results (default 50).")
|
|
213
|
+
},
|
|
214
|
+
"Docs Search",
|
|
215
|
+
"Search documentation by title/body (server-side)."
|
|
216
|
+
);
|
|
217
|
+
forwardTool(
|
|
218
|
+
"docs_create_folder",
|
|
219
|
+
{
|
|
220
|
+
name: z.z.string().describe("Folder name."),
|
|
221
|
+
parentId: z.z.string().optional().describe("Parent folder node id (defaults to root).")
|
|
222
|
+
},
|
|
223
|
+
"Docs Create Folder",
|
|
224
|
+
"Create a folder node in the Documentation Library."
|
|
225
|
+
);
|
|
226
|
+
forwardTool(
|
|
227
|
+
"docs_create_doc",
|
|
228
|
+
{
|
|
229
|
+
name: z.z.string().describe("Doc name (e.g. Design.md)."),
|
|
230
|
+
parentId: z.z.string().optional().describe("Parent folder node id (defaults to root)."),
|
|
231
|
+
bodyMarkdown: z.z.string().optional().describe("Markdown body."),
|
|
232
|
+
metadata: z.z.record(z.z.any()).optional().describe("Metadata object (JSON).")
|
|
233
|
+
},
|
|
234
|
+
"Docs Create Doc",
|
|
235
|
+
"Create a document node in the Documentation Library."
|
|
236
|
+
);
|
|
237
|
+
forwardTool(
|
|
238
|
+
"docs_claim",
|
|
239
|
+
{
|
|
240
|
+
nodeId: z.z.string().describe("Document node id."),
|
|
241
|
+
leaseMs: z.z.number().int().positive().optional().describe("Lease TTL (ms).")
|
|
242
|
+
},
|
|
243
|
+
"Docs Claim",
|
|
244
|
+
"Claim a documentation document for editing (exclusive lease)."
|
|
245
|
+
);
|
|
246
|
+
forwardTool(
|
|
247
|
+
"docs_release",
|
|
248
|
+
{
|
|
249
|
+
nodeId: z.z.string().describe("Document node id.")
|
|
250
|
+
},
|
|
251
|
+
"Docs Release",
|
|
252
|
+
"Release a documentation document lease."
|
|
253
|
+
);
|
|
254
|
+
forwardTool(
|
|
255
|
+
"docs_update",
|
|
256
|
+
{
|
|
257
|
+
nodeId: z.z.string().describe("Document node id."),
|
|
258
|
+
name: z.z.string().optional().describe("Optional new name (rename; index.md cannot be renamed)."),
|
|
259
|
+
bodyMarkdown: z.z.string().optional().describe("Markdown body."),
|
|
260
|
+
metadata: z.z.record(z.z.any()).optional().describe("Metadata object (JSON)."),
|
|
261
|
+
expectedBodyVersion: z.z.number().int().nonnegative().optional().describe("Optional optimistic concurrency check.")
|
|
262
|
+
},
|
|
263
|
+
"Docs Update",
|
|
264
|
+
"Update a documentation document. Claims the lease automatically if required."
|
|
265
|
+
);
|
|
266
|
+
forwardTool(
|
|
267
|
+
"docs_delete",
|
|
268
|
+
{
|
|
269
|
+
nodeId: z.z.string().describe("Node id (folder or document).")
|
|
270
|
+
},
|
|
271
|
+
"Docs Delete",
|
|
272
|
+
"Delete a documentation node (folders must be empty; deleting docs requires active lease; index.md cannot be deleted)."
|
|
273
|
+
);
|
|
274
|
+
forwardTool(
|
|
275
|
+
"docs_import",
|
|
276
|
+
{
|
|
277
|
+
entries: z.z.array(
|
|
278
|
+
z.z.object({
|
|
279
|
+
path: z.z.string().describe("Relative path (within the imported folder)."),
|
|
280
|
+
bodyMarkdown: z.z.string().describe("Markdown content.")
|
|
281
|
+
})
|
|
282
|
+
).describe("Markdown entries to import.")
|
|
283
|
+
},
|
|
284
|
+
"Docs Import",
|
|
285
|
+
"Import markdown files into the Documentation Library (copy into backend DB)."
|
|
286
|
+
);
|
|
287
|
+
forwardTool(
|
|
288
|
+
"unreal_latest_screenshots",
|
|
289
|
+
{
|
|
290
|
+
uprojectPath: z.z.string().describe("Absolute path to the .uproject file."),
|
|
291
|
+
limit: z.z.number().int().positive().optional().describe("Max number of screenshots to return (default 12)."),
|
|
292
|
+
includeBase64: z.z.boolean().optional().describe("Include base64 image data in the payload (default false)."),
|
|
293
|
+
maxBytesPerImage: z.z.number().int().positive().optional().describe("Max bytes per image when includeBase64=true (default 2500000).")
|
|
294
|
+
},
|
|
295
|
+
"Latest Unreal Screenshots",
|
|
296
|
+
"Fetch the latest PNG screenshots from Saved/Screenshots/Flockbay and return views for the UI to display."
|
|
297
|
+
);
|
|
298
|
+
forwardTool(
|
|
299
|
+
"unreal_mcp_command",
|
|
300
|
+
{
|
|
301
|
+
type: z.z.string().describe('UnrealMCP command type (e.g. "get_actors_in_level", "spawn_actor").'),
|
|
302
|
+
params: z.z.record(z.z.any()).optional().describe("Optional params object for the command."),
|
|
303
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
304
|
+
},
|
|
305
|
+
"Unreal Editor Command (UnrealMCP)",
|
|
306
|
+
"Send a single UnrealMCP command to the running Unreal Editor (engine plugin) and return the JSON response."
|
|
307
|
+
);
|
|
308
|
+
forwardTool(
|
|
309
|
+
"unreal_mcp_get_actors_in_level",
|
|
310
|
+
{
|
|
311
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
312
|
+
},
|
|
313
|
+
"Unreal Actors In Level (UnrealMCP)",
|
|
314
|
+
"List all actors in the current Unreal Editor level via the UnrealMCP engine plugin."
|
|
315
|
+
);
|
|
316
|
+
forwardTool(
|
|
317
|
+
"unreal_mcp_get_play_in_editor_status",
|
|
318
|
+
{
|
|
319
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
320
|
+
},
|
|
321
|
+
"Unreal Play Status (PIE)",
|
|
322
|
+
"Get Play-In-Editor status from the UnrealMCP engine plugin."
|
|
323
|
+
);
|
|
324
|
+
forwardTool(
|
|
325
|
+
"unreal_mcp_editor_health",
|
|
326
|
+
{
|
|
327
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 1500).")
|
|
328
|
+
},
|
|
329
|
+
"Unreal Editor Health (UnrealMCP)",
|
|
330
|
+
"Best-effort health check for Unreal Editor + UnrealMCP (detects if the editor is reachable)."
|
|
331
|
+
);
|
|
332
|
+
forwardTool(
|
|
333
|
+
"unreal_mcp_play_in_editor",
|
|
334
|
+
{
|
|
335
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
336
|
+
},
|
|
337
|
+
"Unreal Play In Editor (Viewport)",
|
|
338
|
+
"Start Play-In-Editor (PIE) in the active editor viewport via the UnrealMCP engine plugin."
|
|
339
|
+
);
|
|
340
|
+
forwardTool(
|
|
341
|
+
"unreal_mcp_play_in_editor_windowed",
|
|
342
|
+
{
|
|
343
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
344
|
+
},
|
|
345
|
+
"Unreal Play In Editor (New Window)",
|
|
346
|
+
"Start Play-In-Editor (PIE) in a new editor window via the UnrealMCP engine plugin."
|
|
347
|
+
);
|
|
348
|
+
forwardTool(
|
|
349
|
+
"unreal_mcp_stop_play_in_editor",
|
|
350
|
+
{
|
|
351
|
+
timeoutMs: z.z.number().int().positive().optional().describe("Socket timeout in ms (default 5000).")
|
|
352
|
+
},
|
|
353
|
+
"Unreal Stop Play In Editor",
|
|
354
|
+
"Stop a running Play-In-Editor session via the UnrealMCP engine plugin."
|
|
355
|
+
);
|
|
356
|
+
forwardTool(
|
|
357
|
+
"unreal_mechanic_run",
|
|
358
|
+
{
|
|
359
|
+
uprojectPath: z.z.string().describe("Absolute path to the .uproject file."),
|
|
360
|
+
engineRoot: z.z.string().optional().describe(
|
|
361
|
+
"Unreal Engine install root (e.g. /Users/Shared/Epic Games/UE_5.7). Defaults to UE_ENGINE_ROOT / ENGINE_ROOT env vars."
|
|
362
|
+
),
|
|
363
|
+
slug: z.z.string().optional().describe("Optional slug used for naming the test map (default: dash)."),
|
|
364
|
+
prompt: z.z.string().optional().describe("Optional prompt string to record in the receipt."),
|
|
365
|
+
cooldownSeconds: z.z.number().optional().describe("Dash cooldown seconds (default 1.0)."),
|
|
366
|
+
staminaCost: z.z.number().optional().describe("Dash stamina cost (default 20.0)."),
|
|
367
|
+
dashStrength: z.z.number().optional().describe("Dash horizontal strength (default 1200.0)."),
|
|
368
|
+
dashUpwardStrength: z.z.number().optional().describe("Dash upward strength (default 0.0).")
|
|
369
|
+
},
|
|
370
|
+
"Unreal Mechanic Builder (Dash MVP)",
|
|
371
|
+
"Create a project-safe mechanic test map (Parallel mode) and prove it works with Flockbay screenshot evidence. V1 supports dash only."
|
|
372
|
+
);
|
|
373
|
+
const stdio = new stdio_js.StdioServerTransport();
|
|
374
|
+
await server.connect(stdio);
|
|
375
|
+
}
|
|
376
|
+
main().catch((err) => {
|
|
377
|
+
try {
|
|
378
|
+
process.stderr.write(`[flockbay-mcp] Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
379
|
+
`);
|
|
380
|
+
} finally {
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
});
|