relaycast 0.3.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +35 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +452 -126
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +21 -26
- package/dist/commands/agent.d.ts +0 -3
- package/dist/commands/agent.d.ts.map +0 -1
- package/dist/commands/agent.js +0 -51
- package/dist/commands/agent.js.map +0 -1
- package/dist/commands/billing.d.ts +0 -3
- package/dist/commands/billing.d.ts.map +0 -1
- package/dist/commands/billing.js +0 -37
- package/dist/commands/billing.js.map +0 -1
- package/dist/commands/channel.d.ts +0 -3
- package/dist/commands/channel.d.ts.map +0 -1
- package/dist/commands/channel.js +0 -67
- package/dist/commands/channel.js.map +0 -1
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -23
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/files.d.ts +0 -3
- package/dist/commands/files.d.ts.map +0 -1
- package/dist/commands/files.js +0 -52
- package/dist/commands/files.js.map +0 -1
- package/dist/commands/messaging.d.ts +0 -3
- package/dist/commands/messaging.d.ts.map +0 -1
- package/dist/commands/messaging.js +0 -54
- package/dist/commands/messaging.js.map +0 -1
- package/dist/commands/openclaw.d.ts +0 -3
- package/dist/commands/openclaw.d.ts.map +0 -1
- package/dist/commands/openclaw.js +0 -51
- package/dist/commands/openclaw.js.map +0 -1
- package/dist/commands/reactions.d.ts +0 -3
- package/dist/commands/reactions.d.ts.map +0 -1
- package/dist/commands/reactions.js +0 -32
- package/dist/commands/reactions.js.map +0 -1
- package/dist/commands/read.d.ts +0 -3
- package/dist/commands/read.d.ts.map +0 -1
- package/dist/commands/read.js +0 -80
- package/dist/commands/read.js.map +0 -1
- package/dist/commands/search.d.ts +0 -3
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -31
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/telemetry.d.ts +0 -4
- package/dist/commands/telemetry.d.ts.map +0 -1
- package/dist/commands/telemetry.js +0 -45
- package/dist/commands/telemetry.js.map +0 -1
- package/dist/commands/workspace.d.ts +0 -3
- package/dist/commands/workspace.d.ts.map +0 -1
- package/dist/commands/workspace.js +0 -35
- package/dist/commands/workspace.js.map +0 -1
- package/dist/config.d.ts +0 -9
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -29
- package/dist/config.js.map +0 -1
- package/dist/telemetry.d.ts +0 -17
- package/dist/telemetry.d.ts.map +0 -1
- package/dist/telemetry.js +0 -214
- package/dist/telemetry.js.map +0 -1
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACnD,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,CAAC;AAEH,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type WritableStreamLike = {
|
|
2
|
+
write(chunk: string): unknown;
|
|
3
|
+
};
|
|
4
|
+
type EnvLike = Record<string, string | undefined>;
|
|
5
|
+
type JsonObject = Record<string, unknown>;
|
|
6
|
+
type JsonSchema = {
|
|
7
|
+
type?: string | string[];
|
|
8
|
+
properties?: Record<string, JsonSchema>;
|
|
9
|
+
items?: JsonSchema;
|
|
10
|
+
};
|
|
11
|
+
type ToolDefinition = {
|
|
12
|
+
name: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
inputSchema?: JsonSchema;
|
|
16
|
+
};
|
|
17
|
+
type CliIo = {
|
|
18
|
+
stdout: WritableStreamLike;
|
|
19
|
+
stderr: WritableStreamLike;
|
|
20
|
+
env?: EnvLike;
|
|
21
|
+
};
|
|
22
|
+
type CliConfig = {
|
|
23
|
+
apiKey?: string;
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
agentToken?: string;
|
|
26
|
+
agentName?: string;
|
|
27
|
+
agentType?: 'agent' | 'human';
|
|
28
|
+
strictAgentName?: boolean;
|
|
29
|
+
workspacesJson?: string;
|
|
30
|
+
defaultWorkspace?: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function runCli(argv: string[], io: CliIo): Promise<number>;
|
|
33
|
+
export declare function listCliTools(config?: CliConfig): Promise<ToolDefinition[]>;
|
|
34
|
+
export declare function callCliTool(name: string, args: JsonObject, config?: CliConfig): Promise<unknown>;
|
|
35
|
+
export {};
|
|
3
36
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,KAAK,kBAAkB,GAAG;IAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAC5D,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAClD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC1C,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,CAAC;AACF,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B,CAAC;AACF,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAQF,KAAK,SAAS,GAAG;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAkBF,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDvE;AAED,wBAAsB,YAAY,CAAC,MAAM,GAAE,SAAc,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAQpF;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,SAAc,GACrB,OAAO,CAAC,OAAO,CAAC,CAOlB"}
|
package/dist/index.js
CHANGED
|
@@ -1,137 +1,463 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
3
|
+
import { createRelayMcpServer, parseWorkspaceEnv, } from '@relaycast/mcp';
|
|
4
|
+
import { CLI_VERSION } from './version.js';
|
|
5
|
+
const GLOBAL_FLAG_NAMES = new Set([
|
|
6
|
+
'relay-api-key',
|
|
7
|
+
'relay-base-url',
|
|
8
|
+
'relay-agent-token',
|
|
9
|
+
'relay-agent-name',
|
|
10
|
+
'relay-agent-type',
|
|
11
|
+
'relay-strict-agent-name',
|
|
12
|
+
'relay-workspaces-json',
|
|
13
|
+
'relay-default-workspace',
|
|
14
|
+
'json',
|
|
15
|
+
'help',
|
|
16
|
+
'h',
|
|
17
|
+
]);
|
|
18
|
+
const TOOL_JSON_FLAG_NAMES = new Set(['json-args', 'args-json']);
|
|
19
|
+
export async function runCli(argv, io) {
|
|
20
|
+
try {
|
|
21
|
+
if (argv.length === 1 && (argv[0] === 'version' || argv[0] === '--version' || argv[0] === '-v')) {
|
|
22
|
+
io.stdout.write(`relaycast ${CLI_VERSION}\n`);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const parsed = parseCliArgs(argv, io.env ?? process.env);
|
|
26
|
+
if (parsed.command === 'version') {
|
|
27
|
+
io.stdout.write(`relaycast ${CLI_VERSION}\n`);
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
const session = await createCliMcpSession(parsed.config);
|
|
31
|
+
try {
|
|
32
|
+
const tools = await session.listTools();
|
|
33
|
+
const toolDefinitions = tools.tools;
|
|
34
|
+
if (!parsed.command || parsed.command === 'help' || parsed.command === '--help' || parsed.command === '-h') {
|
|
35
|
+
io.stdout.write(formatHelp(toolDefinitions));
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
if (parsed.command === 'tools' || parsed.command === 'tool.list') {
|
|
39
|
+
if (parsed.outputJson) {
|
|
40
|
+
io.stdout.write(`${JSON.stringify(toolDefinitions, null, 2)}\n`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
io.stdout.write(formatToolList(toolDefinitions));
|
|
44
|
+
}
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
const tool = toolDefinitions.find((candidate) => candidate.name === parsed.command);
|
|
48
|
+
if (parsed.help) {
|
|
49
|
+
io.stdout.write(formatToolHelp(parsed.command, tool));
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
const toolArgs = parseToolArgs(parsed.commandArgs, tool?.inputSchema);
|
|
53
|
+
const result = await session.callTool(parsed.command, toolArgs);
|
|
54
|
+
writeToolResult(io.stdout, result, parsed.outputJson);
|
|
55
|
+
return isToolErrorResult(result) ? 1 : 0;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await session.close();
|
|
59
|
+
}
|
|
36
60
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
catch (err) {
|
|
62
|
+
io.stderr.write(`${formatError(err)}\n`);
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function listCliTools(config = {}) {
|
|
67
|
+
const session = await createCliMcpSession(config);
|
|
68
|
+
try {
|
|
69
|
+
const tools = await session.listTools();
|
|
70
|
+
return tools.tools;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
await session.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function callCliTool(name, args, config = {}) {
|
|
77
|
+
const session = await createCliMcpSession(config);
|
|
78
|
+
try {
|
|
79
|
+
return await session.callTool(name, args);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await session.close();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function parseCliArgs(argv, env) {
|
|
86
|
+
const config = {
|
|
87
|
+
apiKey: env.RELAY_API_KEY,
|
|
88
|
+
baseUrl: env.RELAY_BASE_URL,
|
|
89
|
+
agentToken: env.RELAY_AGENT_TOKEN,
|
|
90
|
+
agentName: env.RELAY_AGENT_NAME,
|
|
91
|
+
agentType: parseAgentType(env.RELAY_AGENT_TYPE),
|
|
92
|
+
strictAgentName: parseBooleanFlag(env.RELAY_STRICT_AGENT_NAME),
|
|
93
|
+
workspacesJson: env.RELAY_WORKSPACES_JSON,
|
|
94
|
+
defaultWorkspace: env.RELAY_DEFAULT_WORKSPACE,
|
|
95
|
+
};
|
|
96
|
+
let outputJson = false;
|
|
97
|
+
let help = false;
|
|
98
|
+
let command = null;
|
|
99
|
+
const commandArgs = [];
|
|
100
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
101
|
+
const token = argv[i];
|
|
102
|
+
if (!command && isFlag(token)) {
|
|
103
|
+
const { name, inlineValue, negated } = splitFlag(token);
|
|
104
|
+
if (negated || !GLOBAL_FLAG_NAMES.has(name)) {
|
|
105
|
+
throw new Error(`Unknown global option "${token}". Put tool arguments after the tool name.`);
|
|
106
|
+
}
|
|
107
|
+
const value = readGlobalFlagValue(argv, i, name, inlineValue);
|
|
108
|
+
if (value.consumed)
|
|
109
|
+
i += 1;
|
|
110
|
+
applyGlobalFlag(config, name, value.value, () => { outputJson = true; }, () => { help = true; });
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (!command) {
|
|
114
|
+
command = token;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (isFlag(token)) {
|
|
118
|
+
const { name, inlineValue, negated } = splitFlag(token);
|
|
119
|
+
if (!negated && GLOBAL_FLAG_NAMES.has(name)) {
|
|
120
|
+
const value = readGlobalFlagValue(argv, i, name, inlineValue);
|
|
121
|
+
if (value.consumed)
|
|
122
|
+
i += 1;
|
|
123
|
+
applyGlobalFlag(config, name, value.value, () => { outputJson = true; }, () => { help = true; });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
commandArgs.push(token);
|
|
128
|
+
}
|
|
129
|
+
return { command, commandArgs, config, outputJson, help };
|
|
130
|
+
}
|
|
131
|
+
async function createCliMcpSession(config) {
|
|
132
|
+
const options = {
|
|
133
|
+
apiKey: config.apiKey,
|
|
134
|
+
baseUrl: config.baseUrl,
|
|
135
|
+
agentToken: config.agentToken,
|
|
136
|
+
agentName: config.agentName,
|
|
137
|
+
agentType: config.agentType,
|
|
138
|
+
strictAgentName: config.strictAgentName,
|
|
139
|
+
defaultWorkspace: config.defaultWorkspace,
|
|
140
|
+
workspaces: config.workspacesJson ? parseWorkspaceEnv(config.workspacesJson) : undefined,
|
|
141
|
+
telemetryTransport: 'stdio',
|
|
142
|
+
};
|
|
143
|
+
const server = createRelayMcpServer(options);
|
|
144
|
+
const client = new Client({ name: 'relaycast', version: CLI_VERSION });
|
|
145
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
146
|
+
await Promise.all([
|
|
147
|
+
client.connect(clientTransport),
|
|
148
|
+
server.connect(serverTransport),
|
|
149
|
+
]);
|
|
150
|
+
return {
|
|
151
|
+
listTools: () => client.listTools(),
|
|
152
|
+
callTool: (name, args) => client.callTool({ name, arguments: args }),
|
|
153
|
+
close: async () => {
|
|
154
|
+
await Promise.allSettled([
|
|
155
|
+
client.close(),
|
|
156
|
+
server.close(),
|
|
157
|
+
]);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function parseToolArgs(argv, inputSchema) {
|
|
162
|
+
const jsonFlagIndex = argv.findIndex((arg) => isFlag(arg) && TOOL_JSON_FLAG_NAMES.has(splitFlag(arg).name));
|
|
163
|
+
if (jsonFlagIndex >= 0) {
|
|
164
|
+
const token = argv[jsonFlagIndex];
|
|
165
|
+
const { inlineValue } = splitFlag(token);
|
|
166
|
+
const raw = inlineValue ?? argv[jsonFlagIndex + 1];
|
|
167
|
+
if (!raw) {
|
|
168
|
+
throw new Error(`Missing value for ${token}`);
|
|
169
|
+
}
|
|
170
|
+
const parsed = JSON.parse(raw);
|
|
171
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
172
|
+
throw new Error(`${token} must be a JSON object`);
|
|
173
|
+
}
|
|
174
|
+
return parsed;
|
|
45
175
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
176
|
+
const args = {};
|
|
177
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
178
|
+
const token = argv[i];
|
|
179
|
+
if (!isFlag(token)) {
|
|
180
|
+
throw new Error(`Unexpected positional argument "${token}". Use --name value arguments.`);
|
|
181
|
+
}
|
|
182
|
+
const { name, inlineValue, negated } = splitFlag(token);
|
|
183
|
+
const key = normalizeArgName(name);
|
|
184
|
+
const schema = inputSchema?.properties?.[key];
|
|
185
|
+
let rawValue;
|
|
186
|
+
if (negated) {
|
|
187
|
+
rawValue = false;
|
|
188
|
+
}
|
|
189
|
+
else if (inlineValue != null) {
|
|
190
|
+
rawValue = inlineValue;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const isBoolean = schemaHasType(schema, 'boolean');
|
|
194
|
+
const value = readFlagValue(argv, i, name, isBoolean);
|
|
195
|
+
rawValue = value.value;
|
|
196
|
+
if (value.consumed)
|
|
197
|
+
i += 1;
|
|
198
|
+
}
|
|
199
|
+
const value = coerceToolValue(rawValue, schema);
|
|
200
|
+
appendArgValue(args, key, value, schema);
|
|
201
|
+
}
|
|
202
|
+
return args;
|
|
203
|
+
}
|
|
204
|
+
function formatHelp(tools) {
|
|
205
|
+
return [
|
|
206
|
+
'relaycast - Relaycast command line tools',
|
|
207
|
+
'',
|
|
208
|
+
'Usage:',
|
|
209
|
+
' relaycast tools',
|
|
210
|
+
' relaycast <mcp-tool-name> [--arg value]',
|
|
211
|
+
' relaycast <mcp-tool-name> --json-args \'{"key":"value"}\'',
|
|
212
|
+
'',
|
|
213
|
+
'Global options:',
|
|
214
|
+
' --relay-api-key <key> Workspace key, defaults to RELAY_API_KEY',
|
|
215
|
+
' --relay-base-url <url> API base URL, defaults to RELAY_BASE_URL',
|
|
216
|
+
' --relay-agent-token <token> Agent token, defaults to RELAY_AGENT_TOKEN',
|
|
217
|
+
' --relay-agent-name <name> Agent name, defaults to RELAY_AGENT_NAME',
|
|
218
|
+
' --json Print raw JSON output',
|
|
219
|
+
'',
|
|
220
|
+
'Commands:',
|
|
221
|
+
formatToolList(tools).trimEnd(),
|
|
222
|
+
].join('\n') + '\n';
|
|
223
|
+
}
|
|
224
|
+
function formatToolList(tools) {
|
|
225
|
+
const width = tools.reduce((max, tool) => Math.max(max, tool.name.length), 0);
|
|
226
|
+
return tools
|
|
227
|
+
.map((tool) => {
|
|
228
|
+
const summary = tool.title ?? firstSentence(tool.description) ?? '';
|
|
229
|
+
return ` ${tool.name.padEnd(width)} ${summary}`.trimEnd();
|
|
230
|
+
})
|
|
231
|
+
.join('\n') + '\n';
|
|
232
|
+
}
|
|
233
|
+
function formatToolHelp(command, tool) {
|
|
234
|
+
if (!tool) {
|
|
235
|
+
return [
|
|
236
|
+
`No MCP tool named "${command}" was found in the tool list.`,
|
|
237
|
+
'Legacy MCP aliases are still accepted when called directly.',
|
|
238
|
+
'',
|
|
239
|
+
`Usage: relaycast ${command} --json-args '{"key":"value"}'`,
|
|
240
|
+
].join('\n') + '\n';
|
|
241
|
+
}
|
|
242
|
+
const lines = [
|
|
243
|
+
`${tool.name}${tool.title ? ` - ${tool.title}` : ''}`,
|
|
244
|
+
'',
|
|
245
|
+
tool.description ?? '',
|
|
246
|
+
'',
|
|
247
|
+
`Usage: relaycast ${tool.name} [--arg value]`,
|
|
248
|
+
];
|
|
249
|
+
const properties = tool.inputSchema?.properties ?? {};
|
|
250
|
+
const argLines = Object.entries(properties).map(([name, schema]) => ` --${name.replace(/_/g, '-')} ${formatSchemaType(schema)}`);
|
|
251
|
+
if (argLines.length) {
|
|
252
|
+
lines.push('', 'Arguments:', ...argLines);
|
|
253
|
+
}
|
|
254
|
+
return lines.filter((line, index) => line || index !== 2).join('\n') + '\n';
|
|
255
|
+
}
|
|
256
|
+
function writeToolResult(stdout, result, rawJson) {
|
|
257
|
+
if (rawJson) {
|
|
258
|
+
stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
52
259
|
return;
|
|
53
260
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
source_surface: 'cli',
|
|
58
|
-
message_kind: 'group_dm',
|
|
59
|
-
participants_count: participants,
|
|
60
|
-
command: commandPath,
|
|
61
|
-
});
|
|
261
|
+
const structured = getStructuredContent(result);
|
|
262
|
+
if (structured !== undefined) {
|
|
263
|
+
stdout.write(`${JSON.stringify(structured, null, 2)}\n`);
|
|
62
264
|
return;
|
|
63
265
|
}
|
|
64
|
-
|
|
65
|
-
|
|
266
|
+
const contentText = getTextContent(result);
|
|
267
|
+
if (contentText) {
|
|
268
|
+
stdout.write(`${contentText}\n`);
|
|
66
269
|
return;
|
|
67
270
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
271
|
+
stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
272
|
+
}
|
|
273
|
+
function isToolErrorResult(result) {
|
|
274
|
+
if (!result || typeof result !== 'object')
|
|
275
|
+
return false;
|
|
276
|
+
return result.isError === true;
|
|
277
|
+
}
|
|
278
|
+
function getStructuredContent(result) {
|
|
279
|
+
if (!result || typeof result !== 'object')
|
|
280
|
+
return undefined;
|
|
281
|
+
return result.structuredContent;
|
|
282
|
+
}
|
|
283
|
+
function getTextContent(result) {
|
|
284
|
+
if (!result || typeof result !== 'object')
|
|
285
|
+
return null;
|
|
286
|
+
const content = result.content;
|
|
287
|
+
if (!Array.isArray(content))
|
|
288
|
+
return null;
|
|
289
|
+
const parts = content
|
|
290
|
+
.map((item) => {
|
|
291
|
+
if (!item || typeof item !== 'object')
|
|
292
|
+
return null;
|
|
293
|
+
const text = item.text;
|
|
294
|
+
return typeof text === 'string' ? text : null;
|
|
295
|
+
})
|
|
296
|
+
.filter((item) => item != null);
|
|
297
|
+
return parts.length ? parts.join('\n') : null;
|
|
298
|
+
}
|
|
299
|
+
function splitFlag(token) {
|
|
300
|
+
const trimmed = token.replace(/^--?/, '');
|
|
301
|
+
const eqIndex = trimmed.indexOf('=');
|
|
302
|
+
const rawName = eqIndex >= 0 ? trimmed.slice(0, eqIndex) : trimmed;
|
|
303
|
+
const negated = rawName.startsWith('no-');
|
|
304
|
+
return {
|
|
305
|
+
name: negated ? rawName.slice(3) : rawName,
|
|
306
|
+
inlineValue: eqIndex >= 0 ? trimmed.slice(eqIndex + 1) : undefined,
|
|
307
|
+
negated,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function isFlag(token) {
|
|
311
|
+
return token.startsWith('-') && token.length > 1;
|
|
312
|
+
}
|
|
313
|
+
function readFlagValue(argv, index, flagName, allowBooleanDefault = false) {
|
|
314
|
+
const next = argv[index + 1];
|
|
315
|
+
if (!next || isFlag(next)) {
|
|
316
|
+
if (allowBooleanDefault) {
|
|
317
|
+
return { value: true, consumed: false };
|
|
318
|
+
}
|
|
319
|
+
throw new Error(`Missing value for --${flagName}`);
|
|
320
|
+
}
|
|
321
|
+
return { value: next, consumed: true };
|
|
322
|
+
}
|
|
323
|
+
function readGlobalFlagValue(argv, index, flagName, inlineValue) {
|
|
324
|
+
if (inlineValue != null) {
|
|
325
|
+
return { value: inlineValue, consumed: false };
|
|
326
|
+
}
|
|
327
|
+
if (flagName === 'json' || flagName === 'help' || flagName === 'h' || flagName === 'relay-strict-agent-name') {
|
|
328
|
+
return { value: true, consumed: false };
|
|
329
|
+
}
|
|
330
|
+
return readFlagValue(argv, index, flagName, false);
|
|
331
|
+
}
|
|
332
|
+
function applyGlobalFlag(config, flag, value, setJson, setHelp) {
|
|
333
|
+
const stringValue = value === true ? undefined : String(value);
|
|
334
|
+
switch (flag) {
|
|
335
|
+
case 'relay-api-key':
|
|
336
|
+
config.apiKey = stringValue;
|
|
337
|
+
break;
|
|
338
|
+
case 'relay-base-url':
|
|
339
|
+
config.baseUrl = stringValue;
|
|
340
|
+
break;
|
|
341
|
+
case 'relay-agent-token':
|
|
342
|
+
config.agentToken = stringValue;
|
|
343
|
+
break;
|
|
344
|
+
case 'relay-agent-name':
|
|
345
|
+
config.agentName = stringValue;
|
|
346
|
+
break;
|
|
347
|
+
case 'relay-agent-type':
|
|
348
|
+
config.agentType = parseAgentType(stringValue);
|
|
349
|
+
break;
|
|
350
|
+
case 'relay-strict-agent-name':
|
|
351
|
+
config.strictAgentName = parseBooleanFlag(value);
|
|
352
|
+
break;
|
|
353
|
+
case 'relay-workspaces-json':
|
|
354
|
+
config.workspacesJson = stringValue;
|
|
355
|
+
break;
|
|
356
|
+
case 'relay-default-workspace':
|
|
357
|
+
config.defaultWorkspace = stringValue;
|
|
358
|
+
break;
|
|
359
|
+
case 'json':
|
|
360
|
+
setJson();
|
|
361
|
+
break;
|
|
362
|
+
case 'help':
|
|
363
|
+
case 'h':
|
|
364
|
+
setHelp();
|
|
365
|
+
break;
|
|
366
|
+
default:
|
|
367
|
+
throw new Error(`Unknown global option "--${flag}"`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function normalizeArgName(name) {
|
|
371
|
+
return name.replace(/-/g, '_');
|
|
372
|
+
}
|
|
373
|
+
function appendArgValue(args, key, value, schema) {
|
|
374
|
+
if (schemaHasType(schema, 'array')) {
|
|
375
|
+
const existing = args[key];
|
|
376
|
+
if (Array.isArray(value)) {
|
|
377
|
+
args[key] = Array.isArray(existing) ? [...existing, ...value] : value;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
args[key] = Array.isArray(existing) ? [...existing, value] : [value];
|
|
381
|
+
}
|
|
91
382
|
return;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const commandPath = getCommandPath(actionCommand);
|
|
97
|
-
if (!commandPath)
|
|
383
|
+
}
|
|
384
|
+
if (Object.prototype.hasOwnProperty.call(args, key)) {
|
|
385
|
+
const existing = args[key];
|
|
386
|
+
args[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
98
387
|
return;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
388
|
+
}
|
|
389
|
+
args[key] = value;
|
|
390
|
+
}
|
|
391
|
+
function coerceToolValue(value, schema) {
|
|
392
|
+
if (typeof value === 'boolean')
|
|
393
|
+
return value;
|
|
394
|
+
if (schemaHasType(schema, 'array')) {
|
|
395
|
+
const parsed = parseJsonIfPossible(value);
|
|
396
|
+
if (Array.isArray(parsed)) {
|
|
397
|
+
return parsed;
|
|
398
|
+
}
|
|
399
|
+
return [coerceToolValue(value, schema?.items)];
|
|
400
|
+
}
|
|
401
|
+
if (schemaHasType(schema, 'object')) {
|
|
402
|
+
return JSON.parse(value);
|
|
403
|
+
}
|
|
404
|
+
if (schemaHasType(schema, 'number') || schemaHasType(schema, 'integer')) {
|
|
405
|
+
const parsed = Number(value);
|
|
406
|
+
if (Number.isNaN(parsed)) {
|
|
407
|
+
throw new Error(`Expected number, received "${value}"`);
|
|
408
|
+
}
|
|
409
|
+
return parsed;
|
|
410
|
+
}
|
|
411
|
+
if (schemaHasType(schema, 'boolean')) {
|
|
412
|
+
return parseBooleanFlag(value);
|
|
413
|
+
}
|
|
414
|
+
return value;
|
|
415
|
+
}
|
|
416
|
+
function schemaHasType(schema, type) {
|
|
417
|
+
if (!schema?.type)
|
|
418
|
+
return false;
|
|
419
|
+
return Array.isArray(schema.type) ? schema.type.includes(type) : schema.type === type;
|
|
420
|
+
}
|
|
421
|
+
function parseJsonIfPossible(value) {
|
|
422
|
+
try {
|
|
423
|
+
return JSON.parse(value);
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function parseBooleanFlag(value) {
|
|
430
|
+
if (value === undefined)
|
|
431
|
+
return undefined;
|
|
432
|
+
if (typeof value === 'boolean')
|
|
433
|
+
return value;
|
|
434
|
+
const normalized = value.trim().toLowerCase();
|
|
435
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized))
|
|
436
|
+
return true;
|
|
437
|
+
if (['0', 'false', 'no', 'off'].includes(normalized))
|
|
438
|
+
return false;
|
|
439
|
+
return undefined;
|
|
440
|
+
}
|
|
441
|
+
function parseAgentType(value) {
|
|
442
|
+
if (value === 'agent' || value === 'human')
|
|
443
|
+
return value;
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
function firstSentence(value) {
|
|
447
|
+
if (!value)
|
|
448
|
+
return undefined;
|
|
449
|
+
const [sentence] = value.split('.');
|
|
450
|
+
return sentence ? `${sentence}.` : value;
|
|
451
|
+
}
|
|
452
|
+
function formatSchemaType(schema) {
|
|
453
|
+
if (!schema.type)
|
|
454
|
+
return 'value';
|
|
455
|
+
return Array.isArray(schema.type) ? schema.type.join('|') : schema.type;
|
|
456
|
+
}
|
|
457
|
+
function formatError(err) {
|
|
458
|
+
if (err instanceof Error) {
|
|
459
|
+
return err.message;
|
|
460
|
+
}
|
|
461
|
+
return String(err);
|
|
462
|
+
}
|
|
137
463
|
//# sourceMappingURL=index.js.map
|