@heyclaude/mcp 0.1.0
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/CHANGELOG.md +9 -0
- package/README.md +132 -0
- package/package.json +81 -0
- package/scripts/validate-endpoint.mjs +200 -0
- package/src/cli-options.js +103 -0
- package/src/cli.js +30 -0
- package/src/endpoint-url.js +32 -0
- package/src/package-metadata.js +7 -0
- package/src/platforms.d.ts +9 -0
- package/src/platforms.js +86 -0
- package/src/registry.d.ts +97 -0
- package/src/registry.js +496 -0
- package/src/remote-proxy.d.ts +19 -0
- package/src/remote-proxy.js +151 -0
- package/src/schemas.d.ts +24 -0
- package/src/schemas.js +198 -0
- package/src/server.d.ts +10 -0
- package/src/server.js +52 -0
- package/src/submissions.d.ts +31 -0
- package/src/submissions.js +569 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
|
|
10
|
+
import { normalizeEndpointUrl, normalizeTimeoutMs } from "./endpoint-url.js";
|
|
11
|
+
import { packageVersion } from "./package-metadata.js";
|
|
12
|
+
import { READ_ONLY_TOOL_NAMES, TOOL_DEFINITIONS } from "./registry.js";
|
|
13
|
+
|
|
14
|
+
function toError(error) {
|
|
15
|
+
if (error instanceof Error) return error;
|
|
16
|
+
return new Error(String(error));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function safeErrorMessage(error) {
|
|
20
|
+
return toError(error).message || "Remote MCP request failed.";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createTimeoutFetch(timeoutMs) {
|
|
24
|
+
return async (url, init = {}) => {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
27
|
+
const inputSignal = init.signal;
|
|
28
|
+
|
|
29
|
+
const abortFromInput = () => controller.abort();
|
|
30
|
+
if (inputSignal) {
|
|
31
|
+
if (inputSignal.aborted) controller.abort();
|
|
32
|
+
else
|
|
33
|
+
inputSignal.addEventListener("abort", abortFromInput, { once: true });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
38
|
+
} finally {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
if (inputSignal) {
|
|
41
|
+
inputSignal.removeEventListener("abort", abortFromInput);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function invalidToolResult(name) {
|
|
48
|
+
return {
|
|
49
|
+
isError: true,
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: JSON.stringify(
|
|
54
|
+
{
|
|
55
|
+
ok: false,
|
|
56
|
+
error: {
|
|
57
|
+
code: "invalid_request",
|
|
58
|
+
message: `Unknown or unsupported HeyClaude MCP tool: ${name}`,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
2,
|
|
63
|
+
),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function errorToolResult(error) {
|
|
70
|
+
return {
|
|
71
|
+
isError: true,
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: JSON.stringify(
|
|
76
|
+
{
|
|
77
|
+
ok: false,
|
|
78
|
+
error: {
|
|
79
|
+
code: "remote_mcp_error",
|
|
80
|
+
message: safeErrorMessage(error),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
null,
|
|
84
|
+
2,
|
|
85
|
+
),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function createRemoteMcpProxyServer(options = {}) {
|
|
92
|
+
const endpointUrl = normalizeEndpointUrl(options.url);
|
|
93
|
+
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
94
|
+
const client = new Client({
|
|
95
|
+
name: "heyclaude-mcp-stdio-proxy",
|
|
96
|
+
version: packageVersion,
|
|
97
|
+
});
|
|
98
|
+
const remoteTransport = new StreamableHTTPClientTransport(endpointUrl, {
|
|
99
|
+
fetch: createTimeoutFetch(timeoutMs),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await client.connect(remoteTransport, { timeout: timeoutMs });
|
|
103
|
+
|
|
104
|
+
const server = new Server(
|
|
105
|
+
{
|
|
106
|
+
name: "heyclaude-registry",
|
|
107
|
+
version: packageVersion,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
capabilities: {
|
|
111
|
+
tools: {},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
117
|
+
tools: TOOL_DEFINITIONS,
|
|
118
|
+
}));
|
|
119
|
+
|
|
120
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
121
|
+
const name = request.params.name;
|
|
122
|
+
if (!READ_ONLY_TOOL_NAMES.includes(name)) {
|
|
123
|
+
return invalidToolResult(name);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
return await client.callTool(
|
|
128
|
+
{
|
|
129
|
+
name,
|
|
130
|
+
arguments: request.params.arguments || {},
|
|
131
|
+
},
|
|
132
|
+
undefined,
|
|
133
|
+
{ timeout: timeoutMs },
|
|
134
|
+
);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return errorToolResult(error);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
server.onclose = () => {
|
|
141
|
+
client.close().catch(() => {});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return { server, client, endpointUrl, timeoutMs };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function runRemoteStdioProxy(options = {}) {
|
|
148
|
+
const { server } = await createRemoteMcpProxyServer(options);
|
|
149
|
+
const transport = new StdioServerTransport();
|
|
150
|
+
await server.connect(transport);
|
|
151
|
+
}
|
package/src/schemas.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const SearchRegistryInputSchema: z.ZodType;
|
|
4
|
+
export const EntryDetailInputSchema: z.ZodType;
|
|
5
|
+
export const CompatibilityInputSchema: z.ZodType;
|
|
6
|
+
export const InstallGuidanceInputSchema: z.ZodType;
|
|
7
|
+
export const PlatformAdapterInputSchema: z.ZodType;
|
|
8
|
+
export const ListDistributionFeedsInputSchema: z.ZodType;
|
|
9
|
+
export const SubmissionFieldsSchema: z.ZodType;
|
|
10
|
+
export const GetSubmissionSchemaInputSchema: z.ZodType;
|
|
11
|
+
export const ValidateSubmissionDraftInputSchema: z.ZodType;
|
|
12
|
+
export const SearchDuplicateEntriesInputSchema: z.ZodType;
|
|
13
|
+
export const BuildSubmissionUrlsInputSchema: z.ZodType;
|
|
14
|
+
export const CategorySubmissionGuidanceInputSchema: z.ZodType;
|
|
15
|
+
export const TOOL_INPUT_SCHEMAS: Record<string, z.ZodType>;
|
|
16
|
+
|
|
17
|
+
export function jsonSchemaForTool(name: string): Record<string, unknown>;
|
|
18
|
+
export function parseToolArguments(
|
|
19
|
+
name: string,
|
|
20
|
+
args?: Record<string, unknown>,
|
|
21
|
+
): Record<string, unknown>;
|
|
22
|
+
export function formatZodError(
|
|
23
|
+
error: unknown,
|
|
24
|
+
): Array<{ path: string; message: string; code: string }> | null;
|
package/src/schemas.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const pathPart = z
|
|
4
|
+
.string()
|
|
5
|
+
.trim()
|
|
6
|
+
.min(1)
|
|
7
|
+
.max(120)
|
|
8
|
+
.regex(/^[a-z0-9-]+$/, "Use lowercase slug-safe path parts only.");
|
|
9
|
+
|
|
10
|
+
const platform = z.string().trim().min(1).max(80);
|
|
11
|
+
const submissionCategory = z.enum([
|
|
12
|
+
"agents",
|
|
13
|
+
"rules",
|
|
14
|
+
"mcp",
|
|
15
|
+
"skills",
|
|
16
|
+
"hooks",
|
|
17
|
+
"commands",
|
|
18
|
+
"statuslines",
|
|
19
|
+
"collections",
|
|
20
|
+
"guides",
|
|
21
|
+
]);
|
|
22
|
+
const optionalText = z.string().trim().max(4000).optional();
|
|
23
|
+
const optionalLongText = z.string().trim().max(24000).optional();
|
|
24
|
+
const optionalTags = z
|
|
25
|
+
.union([
|
|
26
|
+
z.string().trim().max(1000),
|
|
27
|
+
z.array(z.string().trim().min(1).max(80)).max(20),
|
|
28
|
+
])
|
|
29
|
+
.optional();
|
|
30
|
+
|
|
31
|
+
export const SubmissionFieldsSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
name: optionalText,
|
|
34
|
+
title: optionalText,
|
|
35
|
+
slug: pathPart.optional(),
|
|
36
|
+
category: submissionCategory.optional(),
|
|
37
|
+
github_url: optionalText,
|
|
38
|
+
docs_url: optionalText,
|
|
39
|
+
source_url: optionalText,
|
|
40
|
+
brand_name: optionalText,
|
|
41
|
+
brand_domain: optionalText,
|
|
42
|
+
author: optionalText,
|
|
43
|
+
contact_email: optionalText,
|
|
44
|
+
tags: optionalTags,
|
|
45
|
+
description: optionalLongText,
|
|
46
|
+
card_description: optionalText,
|
|
47
|
+
full_copyable_content: optionalLongText,
|
|
48
|
+
install_command: optionalText,
|
|
49
|
+
usage_snippet: optionalLongText,
|
|
50
|
+
command_syntax: optionalText,
|
|
51
|
+
trigger: optionalText,
|
|
52
|
+
guide_content: optionalLongText,
|
|
53
|
+
items: optionalLongText,
|
|
54
|
+
script_language: optionalText,
|
|
55
|
+
skill_type: optionalText,
|
|
56
|
+
skill_level: optionalText,
|
|
57
|
+
verification_status: optionalText,
|
|
58
|
+
verified_at: optionalText,
|
|
59
|
+
download_url: optionalText,
|
|
60
|
+
config_snippet: optionalLongText,
|
|
61
|
+
retrieval_sources: optionalLongText,
|
|
62
|
+
tested_platforms: optionalText,
|
|
63
|
+
prerequisites: optionalLongText,
|
|
64
|
+
troubleshooting_section: optionalLongText,
|
|
65
|
+
installation_order: optionalText,
|
|
66
|
+
estimated_setup_time: optionalText,
|
|
67
|
+
difficulty: optionalText,
|
|
68
|
+
})
|
|
69
|
+
.strict();
|
|
70
|
+
|
|
71
|
+
export const SearchRegistryInputSchema = z
|
|
72
|
+
.object({
|
|
73
|
+
query: z.string().trim().max(240).optional(),
|
|
74
|
+
category: pathPart.optional(),
|
|
75
|
+
platform: platform.optional(),
|
|
76
|
+
limit: z.number().int().min(1).max(25).optional(),
|
|
77
|
+
})
|
|
78
|
+
.strict();
|
|
79
|
+
|
|
80
|
+
export const EntryDetailInputSchema = z
|
|
81
|
+
.object({
|
|
82
|
+
category: pathPart,
|
|
83
|
+
slug: pathPart,
|
|
84
|
+
})
|
|
85
|
+
.strict();
|
|
86
|
+
|
|
87
|
+
export const CompatibilityInputSchema = z
|
|
88
|
+
.object({
|
|
89
|
+
category: pathPart.optional(),
|
|
90
|
+
slug: pathPart,
|
|
91
|
+
})
|
|
92
|
+
.strict();
|
|
93
|
+
|
|
94
|
+
export const InstallGuidanceInputSchema = z
|
|
95
|
+
.object({
|
|
96
|
+
category: pathPart,
|
|
97
|
+
slug: pathPart,
|
|
98
|
+
platform: platform.optional(),
|
|
99
|
+
})
|
|
100
|
+
.strict();
|
|
101
|
+
|
|
102
|
+
export const PlatformAdapterInputSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
slug: pathPart,
|
|
105
|
+
platform: platform.optional(),
|
|
106
|
+
})
|
|
107
|
+
.strict();
|
|
108
|
+
|
|
109
|
+
export const ListDistributionFeedsInputSchema = z.object({}).strict();
|
|
110
|
+
|
|
111
|
+
export const GetSubmissionSchemaInputSchema = z
|
|
112
|
+
.object({
|
|
113
|
+
category: submissionCategory.optional(),
|
|
114
|
+
})
|
|
115
|
+
.strict();
|
|
116
|
+
|
|
117
|
+
export const ValidateSubmissionDraftInputSchema = z
|
|
118
|
+
.object({
|
|
119
|
+
fields: SubmissionFieldsSchema,
|
|
120
|
+
})
|
|
121
|
+
.strict();
|
|
122
|
+
|
|
123
|
+
export const SearchDuplicateEntriesInputSchema = z
|
|
124
|
+
.object({
|
|
125
|
+
category: pathPart.optional(),
|
|
126
|
+
slug: pathPart.optional(),
|
|
127
|
+
name: z.string().trim().min(1).max(240).optional(),
|
|
128
|
+
title: z.string().trim().min(1).max(240).optional(),
|
|
129
|
+
sourceUrl: z.string().trim().min(1).max(500).optional(),
|
|
130
|
+
brandDomain: z.string().trim().min(1).max(255).optional(),
|
|
131
|
+
limit: z.number().int().min(1).max(10).optional(),
|
|
132
|
+
})
|
|
133
|
+
.strict();
|
|
134
|
+
|
|
135
|
+
export const BuildSubmissionUrlsInputSchema = z
|
|
136
|
+
.object({
|
|
137
|
+
fields: SubmissionFieldsSchema,
|
|
138
|
+
includeIssueBody: z.boolean().optional(),
|
|
139
|
+
})
|
|
140
|
+
.strict();
|
|
141
|
+
|
|
142
|
+
export const CategorySubmissionGuidanceInputSchema = z
|
|
143
|
+
.object({
|
|
144
|
+
category: submissionCategory.optional(),
|
|
145
|
+
})
|
|
146
|
+
.strict();
|
|
147
|
+
|
|
148
|
+
export const TOOL_INPUT_SCHEMAS = {
|
|
149
|
+
search_registry: SearchRegistryInputSchema,
|
|
150
|
+
get_entry_detail: EntryDetailInputSchema,
|
|
151
|
+
get_compatibility: CompatibilityInputSchema,
|
|
152
|
+
get_install_guidance: InstallGuidanceInputSchema,
|
|
153
|
+
get_platform_adapter: PlatformAdapterInputSchema,
|
|
154
|
+
list_distribution_feeds: ListDistributionFeedsInputSchema,
|
|
155
|
+
get_submission_schema: GetSubmissionSchemaInputSchema,
|
|
156
|
+
validate_submission_draft: ValidateSubmissionDraftInputSchema,
|
|
157
|
+
search_duplicate_entries: SearchDuplicateEntriesInputSchema,
|
|
158
|
+
build_submission_urls: BuildSubmissionUrlsInputSchema,
|
|
159
|
+
get_category_submission_guidance: CategorySubmissionGuidanceInputSchema,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
function stripUnsupportedJsonSchemaFields(value) {
|
|
163
|
+
if (Array.isArray(value)) {
|
|
164
|
+
return value.map(stripUnsupportedJsonSchemaFields);
|
|
165
|
+
}
|
|
166
|
+
if (!value || typeof value !== "object") return value;
|
|
167
|
+
|
|
168
|
+
return Object.fromEntries(
|
|
169
|
+
Object.entries(value)
|
|
170
|
+
.filter(([key]) => key !== "$schema")
|
|
171
|
+
.map(([key, nested]) => [key, stripUnsupportedJsonSchemaFields(nested)]),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function jsonSchemaForTool(name) {
|
|
176
|
+
const schema = TOOL_INPUT_SCHEMAS[name];
|
|
177
|
+
if (!schema) {
|
|
178
|
+
throw new Error(`Unknown HeyClaude MCP tool schema: ${name}`);
|
|
179
|
+
}
|
|
180
|
+
return stripUnsupportedJsonSchemaFields(z.toJSONSchema(schema));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function parseToolArguments(name, args = {}) {
|
|
184
|
+
const schema = TOOL_INPUT_SCHEMAS[name];
|
|
185
|
+
if (!schema) {
|
|
186
|
+
throw new Error(`Unknown HeyClaude MCP tool schema: ${name}`);
|
|
187
|
+
}
|
|
188
|
+
return schema.parse(args || {});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function formatZodError(error) {
|
|
192
|
+
if (!(error instanceof z.ZodError)) return null;
|
|
193
|
+
return error.issues.map((issue) => ({
|
|
194
|
+
path: issue.path.join("."),
|
|
195
|
+
message: issue.message,
|
|
196
|
+
code: issue.code,
|
|
197
|
+
}));
|
|
198
|
+
}
|
package/src/server.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { RegistryArtifactLoaders } from "./registry.js";
|
|
3
|
+
|
|
4
|
+
export function createHeyClaudeMcpServer(
|
|
5
|
+
options?: RegistryArtifactLoaders,
|
|
6
|
+
): Server;
|
|
7
|
+
|
|
8
|
+
export function runStdioServer(
|
|
9
|
+
options?: RegistryArtifactLoaders,
|
|
10
|
+
): Promise<void>;
|
package/src/server.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import {
|
|
4
|
+
CallToolRequestSchema,
|
|
5
|
+
ListToolsRequestSchema,
|
|
6
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
|
|
8
|
+
import { packageVersion } from "./package-metadata.js";
|
|
9
|
+
import { callRegistryTool, TOOL_DEFINITIONS } from "./registry.js";
|
|
10
|
+
|
|
11
|
+
export function createHeyClaudeMcpServer(options = {}) {
|
|
12
|
+
const server = new Server(
|
|
13
|
+
{
|
|
14
|
+
name: "heyclaude-registry",
|
|
15
|
+
version: packageVersion,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
capabilities: {
|
|
19
|
+
tools: {},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
25
|
+
tools: TOOL_DEFINITIONS,
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
29
|
+
const result = await callRegistryTool(
|
|
30
|
+
request.params.name,
|
|
31
|
+
request.params.arguments || {},
|
|
32
|
+
options,
|
|
33
|
+
);
|
|
34
|
+
return {
|
|
35
|
+
isError: result.ok === false,
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: JSON.stringify(result, null, 2),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return server;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function runStdioServer(options = {}) {
|
|
49
|
+
const server = createHeyClaudeMcpServer(options);
|
|
50
|
+
const transport = new StdioServerTransport();
|
|
51
|
+
await server.connect(transport);
|
|
52
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const SUBMISSION_SITE_URL: string;
|
|
2
|
+
export const GITHUB_NEW_ISSUE_URL: string;
|
|
3
|
+
|
|
4
|
+
export function slugify(value: string): string;
|
|
5
|
+
export function normalizeSubmissionFields(
|
|
6
|
+
fields?: Record<string, unknown>,
|
|
7
|
+
): Record<string, string>;
|
|
8
|
+
export function buildIssueDraftFromSpec(
|
|
9
|
+
spec: Record<string, unknown>,
|
|
10
|
+
fields?: Record<string, unknown>,
|
|
11
|
+
): Record<string, unknown>;
|
|
12
|
+
export function buildSubmissionUrlsFromSpec(
|
|
13
|
+
spec: Record<string, unknown>,
|
|
14
|
+
args?: Record<string, unknown>,
|
|
15
|
+
): Record<string, unknown>;
|
|
16
|
+
export function getSubmissionSchemaFromSpec(
|
|
17
|
+
spec: Record<string, unknown>,
|
|
18
|
+
args?: Record<string, unknown>,
|
|
19
|
+
): Record<string, unknown>;
|
|
20
|
+
export function validateSubmissionDraftFromSpec(
|
|
21
|
+
spec: Record<string, unknown>,
|
|
22
|
+
args?: Record<string, unknown>,
|
|
23
|
+
): Record<string, unknown>;
|
|
24
|
+
export function searchDuplicateEntries(
|
|
25
|
+
entries?: Array<Record<string, unknown>>,
|
|
26
|
+
args?: Record<string, unknown>,
|
|
27
|
+
): Record<string, unknown>;
|
|
28
|
+
export function getCategorySubmissionGuidanceFromSpec(
|
|
29
|
+
spec: Record<string, unknown>,
|
|
30
|
+
args?: Record<string, unknown>,
|
|
31
|
+
): Record<string, unknown>;
|