@sidecar-ai/compiler 0.1.0-alpha.1 → 0.1.0-alpha.4
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/index.d.ts +10 -1
- package/dist/index.js +377 -21
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ declare function formatDiagnostic(diagnostic: SidecarDiagnostic): string;
|
|
|
27
27
|
|
|
28
28
|
/** Build target profile selected by reserved platform file suffixes. */
|
|
29
29
|
type SidecarTarget = "mcp" | "chatgpt" | "claude";
|
|
30
|
+
/** Host runtime artifact emitted for a build output. */
|
|
31
|
+
type SidecarHost = "node" | "vercel";
|
|
30
32
|
/** Platform suffix chosen for a reserved tool or widget file. */
|
|
31
33
|
type SidecarSourceVariant = "shared" | "openai" | "anthropic";
|
|
32
34
|
/** Tool entry emitted into `manifest.sidecar.json`. */
|
|
@@ -109,6 +111,7 @@ type SidecarCompilerConfig = {
|
|
|
109
111
|
type SidecarManifest = {
|
|
110
112
|
version: 1;
|
|
111
113
|
target: SidecarTarget;
|
|
114
|
+
host: SidecarHost;
|
|
112
115
|
rootDir: string;
|
|
113
116
|
generatedAt: string;
|
|
114
117
|
config: SidecarCompilerConfig;
|
|
@@ -121,6 +124,7 @@ type SidecarManifest = {
|
|
|
121
124
|
/** Options accepted by `buildProject()`. */
|
|
122
125
|
type BuildProjectOptions = {
|
|
123
126
|
rootDir: string;
|
|
127
|
+
host?: SidecarHost;
|
|
124
128
|
outDir?: string;
|
|
125
129
|
plugins?: boolean;
|
|
126
130
|
strict?: boolean;
|
|
@@ -172,4 +176,9 @@ declare function analyzeProjectResources(rootDir: string): Promise<SidecarResour
|
|
|
172
176
|
/** Analyzes one `resource.ts` source file into a compiler manifest entry. */
|
|
173
177
|
declare function analyzeResourceFile(sourceFile: SourceFile, rootDir: string): SidecarResourceManifestEntry;
|
|
174
178
|
|
|
175
|
-
|
|
179
|
+
/** Relative location of the generated server entrypoint inside a build output. */
|
|
180
|
+
declare const SERVER_ENTRYPOINT = "server/index.js";
|
|
181
|
+
/** Relative location of the optional Vercel request-handler shim. */
|
|
182
|
+
declare const VERCEL_ENTRYPOINT = "api/sidecar.js";
|
|
183
|
+
|
|
184
|
+
export { type BuildProjectOptions, CompilerError, type ProjectIdentity, SERVER_ENTRYPOINT, type SidecarCompilerConfig, type SidecarDiagnostic, type SidecarHost, type SidecarManifest, type SidecarPromptManifestEntry, type SidecarResourceManifestEntry, type SidecarResourceTemplateManifestEntry, type SidecarSourceVariant, type SidecarTarget, type SidecarToolManifestEntry, type SidecarWidgetManifestEntry, VERCEL_ENTRYPOINT, analyzeProjectConfig, analyzeProjectPrompts, analyzeProjectResources, analyzeProjectTools, analyzePromptFile, analyzeResourceFile, analyzeToolFile, buildProject, collectProjectDiagnostics, formatDiagnostic };
|
package/dist/index.js
CHANGED
|
@@ -579,12 +579,19 @@ function typeToJsonSchemaInner(type) {
|
|
|
579
579
|
return { anyOf: parts.map((part) => typeToJsonSchema(part)) };
|
|
580
580
|
}
|
|
581
581
|
const properties = type.getProperties();
|
|
582
|
+
const indexType = type.getStringIndexType() ?? type.getNumberIndexType();
|
|
582
583
|
if (properties.length > 0) {
|
|
583
|
-
return objectTypeToSchema(properties);
|
|
584
|
+
return objectTypeToSchema(properties, indexType);
|
|
585
|
+
}
|
|
586
|
+
if (indexType) {
|
|
587
|
+
return {
|
|
588
|
+
type: "object",
|
|
589
|
+
additionalProperties: indexTypeToAdditionalProperties(indexType)
|
|
590
|
+
};
|
|
584
591
|
}
|
|
585
592
|
return {};
|
|
586
593
|
}
|
|
587
|
-
function objectTypeToSchema(properties) {
|
|
594
|
+
function objectTypeToSchema(properties, indexType) {
|
|
588
595
|
const schemaProperties = {};
|
|
589
596
|
const required = [];
|
|
590
597
|
for (const property of properties) {
|
|
@@ -608,9 +615,16 @@ function objectTypeToSchema(properties) {
|
|
|
608
615
|
type: "object",
|
|
609
616
|
properties: schemaProperties,
|
|
610
617
|
required,
|
|
611
|
-
additionalProperties: false
|
|
618
|
+
additionalProperties: indexType ? indexTypeToAdditionalProperties(indexType) : false
|
|
612
619
|
};
|
|
613
620
|
}
|
|
621
|
+
function indexTypeToAdditionalProperties(type) {
|
|
622
|
+
if (type.isAny() || type.isUnknown()) {
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
const schema = typeToJsonSchema(type);
|
|
626
|
+
return Object.keys(schema).length ? schema : true;
|
|
627
|
+
}
|
|
614
628
|
function literalOrPrimitive(type, primitive) {
|
|
615
629
|
if (isLiteralType(type)) {
|
|
616
630
|
return { const: literalValue(type) };
|
|
@@ -679,6 +693,7 @@ import {
|
|
|
679
693
|
Node as Node3,
|
|
680
694
|
SyntaxKind
|
|
681
695
|
} from "ts-morph";
|
|
696
|
+
var CLAUDE_FONT_RESOURCE_DOMAIN = "https://assets.claude.ai";
|
|
682
697
|
async function buildWidgets(rootDir, outDir, tools) {
|
|
683
698
|
const widgets = tools.filter(
|
|
684
699
|
(entry) => Boolean(entry.widget)
|
|
@@ -862,7 +877,7 @@ function widgetMeta(resourceUri, options = {}, target = "mcp") {
|
|
|
862
877
|
function widgetResourceMeta(options = {}, target = "mcp") {
|
|
863
878
|
const csp = stripUndefined3({
|
|
864
879
|
connectDomains: options.csp?.connectDomains ? [...options.csp.connectDomains] : [],
|
|
865
|
-
resourceDomains: options
|
|
880
|
+
resourceDomains: widgetResourceDomains(options, target),
|
|
866
881
|
frameDomains: options.csp?.frameDomains ? [...options.csp.frameDomains] : void 0,
|
|
867
882
|
baseUriDomains: options.csp?.baseUriDomains ? [...options.csp.baseUriDomains] : void 0
|
|
868
883
|
});
|
|
@@ -875,6 +890,13 @@ function widgetResourceMeta(options = {}, target = "mcp") {
|
|
|
875
890
|
});
|
|
876
891
|
return Object.keys(ui).length ? { ui } : void 0;
|
|
877
892
|
}
|
|
893
|
+
function widgetResourceDomains(options, target) {
|
|
894
|
+
const domains = [...options.csp?.resourceDomains ?? []];
|
|
895
|
+
if (target === "claude" && !domains.includes(CLAUDE_FONT_RESOURCE_DOMAIN)) {
|
|
896
|
+
domains.push(CLAUDE_FONT_RESOURCE_DOMAIN);
|
|
897
|
+
}
|
|
898
|
+
return domains;
|
|
899
|
+
}
|
|
878
900
|
function findWidgetDefinition(sourceFile) {
|
|
879
901
|
const call = resolveDefaultExportCall(sourceFile, "widget");
|
|
880
902
|
if (!call) {
|
|
@@ -1460,8 +1482,8 @@ function readStringArrayProperty2(definition, propertyName) {
|
|
|
1460
1482
|
}
|
|
1461
1483
|
|
|
1462
1484
|
// packages/compiler/src/build.ts
|
|
1463
|
-
import { mkdir as
|
|
1464
|
-
import
|
|
1485
|
+
import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
|
|
1486
|
+
import path18 from "path";
|
|
1465
1487
|
|
|
1466
1488
|
// packages/compiler/src/config.ts
|
|
1467
1489
|
import path5 from "path";
|
|
@@ -1878,10 +1900,6 @@ function uniqueMethodNames(names) {
|
|
|
1878
1900
|
});
|
|
1879
1901
|
}
|
|
1880
1902
|
|
|
1881
|
-
// packages/compiler/src/plugins.ts
|
|
1882
|
-
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
1883
|
-
import path14 from "path";
|
|
1884
|
-
|
|
1885
1903
|
// packages/compiler/src/identity.ts
|
|
1886
1904
|
import { readFile as readFile3 } from "fs/promises";
|
|
1887
1905
|
import path8 from "path";
|
|
@@ -1922,6 +1940,10 @@ function readConfigString(configText, key) {
|
|
|
1922
1940
|
return match?.[1];
|
|
1923
1941
|
}
|
|
1924
1942
|
|
|
1943
|
+
// packages/compiler/src/plugins.ts
|
|
1944
|
+
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
1945
|
+
import path14 from "path";
|
|
1946
|
+
|
|
1925
1947
|
// packages/compiler/src/plugin-components/agents.ts
|
|
1926
1948
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
1927
1949
|
import path9 from "path";
|
|
@@ -2366,7 +2388,7 @@ This package was generated by Sidecar.
|
|
|
2366
2388
|
|
|
2367
2389
|
Set \`SIDECAR_MCP_URL\` to the hosted MCP endpoint for this app.
|
|
2368
2390
|
|
|
2369
|
-
For local testing, run \`sidecar dev --tunnel\` and use the
|
|
2391
|
+
For local testing, run \`sidecar dev --tunnel\` and use the validated HTTPS MCP URL it prints. Temporary quick tunnels are public and best-effort; use a configured tunnel/domain or deployed preview for repeatable testing.
|
|
2370
2392
|
|
|
2371
2393
|
Claude/Cowork plugin-specific components such as skills, slash commands, agents, hooks, output styles, themes, monitors, assets, and bin scripts will be emitted here when the source project defines them.
|
|
2372
2394
|
`
|
|
@@ -2777,15 +2799,319 @@ function readStringArrayProperty4(definition, propertyName) {
|
|
|
2777
2799
|
return initializer.getElements().filter(Node8.isStringLiteral).map((element) => element.getLiteralText());
|
|
2778
2800
|
}
|
|
2779
2801
|
|
|
2802
|
+
// packages/compiler/src/server-output.ts
|
|
2803
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2804
|
+
import { mkdir as mkdir8, rm, writeFile as writeFile8 } from "fs/promises";
|
|
2805
|
+
import path17 from "path";
|
|
2806
|
+
import { build as esbuild2 } from "esbuild";
|
|
2807
|
+
var SERVER_ENTRYPOINT = "server/index.js";
|
|
2808
|
+
var VERCEL_ENTRYPOINT = "api/sidecar.js";
|
|
2809
|
+
async function buildServerOutput(rootDir, outDir, manifest, identity, host = "node") {
|
|
2810
|
+
const cacheDir = path17.join(rootDir, ".sidecar", "cache", "server");
|
|
2811
|
+
await mkdir8(cacheDir, { recursive: true });
|
|
2812
|
+
const entryFile = path17.join(cacheDir, "index.ts");
|
|
2813
|
+
await writeFile8(entryFile, renderServerEntry(rootDir, entryFile, manifest, identity));
|
|
2814
|
+
const serverFile = path17.join(outDir, SERVER_ENTRYPOINT);
|
|
2815
|
+
await mkdir8(path17.dirname(serverFile), { recursive: true });
|
|
2816
|
+
await esbuild2({
|
|
2817
|
+
absWorkingDir: rootDir,
|
|
2818
|
+
alias: sidecarBundleAliases(rootDir),
|
|
2819
|
+
banner: {
|
|
2820
|
+
js: `import { createRequire as __sidecarCreateRequire } from "node:module";
|
|
2821
|
+
const require = __sidecarCreateRequire(import.meta.url);`
|
|
2822
|
+
},
|
|
2823
|
+
bundle: true,
|
|
2824
|
+
entryPoints: [entryFile],
|
|
2825
|
+
format: "esm",
|
|
2826
|
+
legalComments: "none",
|
|
2827
|
+
minify: false,
|
|
2828
|
+
nodePaths: [
|
|
2829
|
+
path17.join(rootDir, "node_modules"),
|
|
2830
|
+
path17.join(process.cwd(), "node_modules")
|
|
2831
|
+
],
|
|
2832
|
+
outfile: serverFile,
|
|
2833
|
+
platform: "node",
|
|
2834
|
+
sourcemap: false,
|
|
2835
|
+
target: "node20"
|
|
2836
|
+
});
|
|
2837
|
+
await writeFile8(path17.join(outDir, "package.json"), renderServerPackage(identity));
|
|
2838
|
+
if (host === "vercel") {
|
|
2839
|
+
await mkdir8(path17.join(outDir, "api"), { recursive: true });
|
|
2840
|
+
await writeFile8(path17.join(outDir, VERCEL_ENTRYPOINT), renderVercelEntrypoint());
|
|
2841
|
+
await writeFile8(path17.join(outDir, "vercel.json"), renderVercelConfig());
|
|
2842
|
+
} else {
|
|
2843
|
+
await rm(path17.join(outDir, "api"), { recursive: true, force: true });
|
|
2844
|
+
await rm(path17.join(outDir, "vercel.json"), { force: true });
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
2848
|
+
const entryDir = path17.dirname(entryFile);
|
|
2849
|
+
const tools = manifest.tools;
|
|
2850
|
+
const resources = manifest.resources;
|
|
2851
|
+
const prompts = manifest.prompts;
|
|
2852
|
+
const imports = [
|
|
2853
|
+
`import { readFileSync, realpathSync } from "node:fs";`,
|
|
2854
|
+
`import { createServer } from "node:http";`,
|
|
2855
|
+
`import { pathToFileURL } from "node:url";`,
|
|
2856
|
+
`import { createSidecarHttpHandler } from "@sidecar-ai/server";`,
|
|
2857
|
+
`import { isSidecarAuth } from "@sidecar-ai/auth";`,
|
|
2858
|
+
`import { isSidecarPrompt, isSidecarResource, isSidecarTool } from "@sidecar-ai/core";`,
|
|
2859
|
+
`import { isSidecarProxy } from "@sidecar-ai/server/proxy";`,
|
|
2860
|
+
...tools.map(
|
|
2861
|
+
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
2862
|
+
),
|
|
2863
|
+
...resources.map(
|
|
2864
|
+
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
2865
|
+
),
|
|
2866
|
+
...prompts.map(
|
|
2867
|
+
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
2868
|
+
),
|
|
2869
|
+
existsSync5(path17.join(rootDir, "auth.ts")) ? `import authExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "auth.ts")))};` : `const authExport = undefined;`,
|
|
2870
|
+
existsSync5(path17.join(rootDir, "proxy.ts")) ? `import proxyExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "proxy.ts")))};` : `const proxyExport = undefined;`,
|
|
2871
|
+
existsSync5(path17.join(rootDir, "sidecar.config.ts")) ? `import configExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "sidecar.config.ts")))};` : `const configExport = undefined;`
|
|
2872
|
+
].join("\n");
|
|
2873
|
+
return `${imports}
|
|
2874
|
+
|
|
2875
|
+
const manifest = ${JSON.stringify(manifest, null, 2)};
|
|
2876
|
+
const identity = ${JSON.stringify(identity, null, 2)};
|
|
2877
|
+
|
|
2878
|
+
const loadedAuth = authExport === undefined ? undefined : assertAuth(authExport);
|
|
2879
|
+
const auth = loadedAuth && process.env.SIDECAR_MCP_URL
|
|
2880
|
+
? loadedAuth.withResource(process.env.SIDECAR_MCP_URL)
|
|
2881
|
+
: loadedAuth;
|
|
2882
|
+
const proxy = proxyExport === undefined ? undefined : assertProxy(proxyExport);
|
|
2883
|
+
const runtimeConfig = configExport && typeof configExport === "object" ? configExport : undefined;
|
|
2884
|
+
|
|
2885
|
+
if (auth && !process.env.SIDECAR_MCP_URL) {
|
|
2886
|
+
console.warn("Sidecar auth is enabled. Set SIDECAR_MCP_URL to the public https://.../mcp URL before hosting.");
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
export const handler = createSidecarHttpHandler({
|
|
2890
|
+
name: identity.name,
|
|
2891
|
+
version: identity.version,
|
|
2892
|
+
path: process.env.SIDECAR_MCP_PATH ?? "/mcp",
|
|
2893
|
+
publicUrl: process.env.SIDECAR_PUBLIC_URL ?? process.env.SIDECAR_MCP_URL,
|
|
2894
|
+
auth,
|
|
2895
|
+
proxy,
|
|
2896
|
+
tools: [
|
|
2897
|
+
${tools.map((entry, index) => ` loadTool(${JSON.stringify(entry.sourceFile)}, tool${index}, manifest.tools[${index}].descriptor),`).join("\n")}
|
|
2898
|
+
],
|
|
2899
|
+
resources: [
|
|
2900
|
+
${renderWidgetResources(manifest)}
|
|
2901
|
+
${resources.map((entry, index) => ` loadResource(${JSON.stringify(entry.sourceFile)}, resource${index}, manifest.resources[${index}]),`).join("\n")}
|
|
2902
|
+
],
|
|
2903
|
+
resourceTemplates: manifest.resourceTemplates.map((entry) => ({ descriptor: entry.descriptor })),
|
|
2904
|
+
prompts: [
|
|
2905
|
+
${prompts.map((entry, index) => ` loadPrompt(${JSON.stringify(entry.sourceFile)}, prompt${index}, manifest.prompts[${index}].descriptor),`).join("\n")}
|
|
2906
|
+
],
|
|
2907
|
+
capabilities: {
|
|
2908
|
+
tools: runtimeConfig?.tools ?? manifest.config.tools,
|
|
2909
|
+
resources: runtimeConfig?.resources ?? manifest.config.resources,
|
|
2910
|
+
prompts: runtimeConfig?.prompts ?? manifest.config.prompts,
|
|
2911
|
+
},
|
|
2912
|
+
pagination: runtimeConfig?.pagination ?? {
|
|
2913
|
+
pageSize: manifest.config.pagination.pageSize,
|
|
2914
|
+
},
|
|
2915
|
+
});
|
|
2916
|
+
|
|
2917
|
+
export default handler;
|
|
2918
|
+
|
|
2919
|
+
export const server = createServer(handler);
|
|
2920
|
+
|
|
2921
|
+
if (isDirectRun()) {
|
|
2922
|
+
const port = readPort();
|
|
2923
|
+
const host = process.env.SIDECAR_HOST ?? process.env.HOST ?? "0.0.0.0";
|
|
2924
|
+
server.listen(port, host, () => {
|
|
2925
|
+
const localHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
2926
|
+
console.log(\`MCP running on Streamable HTTP at http://\${localHost}:\${port}\${process.env.SIDECAR_MCP_PATH ?? "/mcp"}\`);
|
|
2927
|
+
});
|
|
2928
|
+
|
|
2929
|
+
process.on("SIGTERM", () => shutdown());
|
|
2930
|
+
process.on("SIGINT", () => shutdown());
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
function loadTool(sourceFile, value, descriptor) {
|
|
2934
|
+
const tool = unwrapRuntimeDefault(value);
|
|
2935
|
+
if (!isSidecarTool(tool)) {
|
|
2936
|
+
throw new Error(\`\${sourceFile} did not default-export a Sidecar tool.\`);
|
|
2937
|
+
}
|
|
2938
|
+
return { tool, descriptor };
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
function loadResource(sourceFile, value, entry) {
|
|
2942
|
+
const resource = unwrapRuntimeDefault(value);
|
|
2943
|
+
if (!isSidecarResource(resource)) {
|
|
2944
|
+
throw new Error(\`\${sourceFile} did not default-export a Sidecar resource.\`);
|
|
2945
|
+
}
|
|
2946
|
+
return {
|
|
2947
|
+
uri: entry.uri,
|
|
2948
|
+
descriptor: entry.descriptor,
|
|
2949
|
+
resource,
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
function loadPrompt(sourceFile, value, descriptor) {
|
|
2954
|
+
const prompt = unwrapRuntimeDefault(value);
|
|
2955
|
+
if (!isSidecarPrompt(prompt)) {
|
|
2956
|
+
throw new Error(\`\${sourceFile} did not default-export a Sidecar prompt.\`);
|
|
2957
|
+
}
|
|
2958
|
+
return { prompt, descriptor };
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
function assertAuth(value) {
|
|
2962
|
+
const authValue = unwrapRuntimeDefault(value);
|
|
2963
|
+
if (!isSidecarAuth(authValue)) {
|
|
2964
|
+
throw new Error("auth.ts must default-export auth({ ... }) from sidecar-ai.");
|
|
2965
|
+
}
|
|
2966
|
+
return authValue;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
function assertProxy(value) {
|
|
2970
|
+
const proxyValue = unwrapRuntimeDefault(value);
|
|
2971
|
+
if (!isSidecarProxy(proxyValue)) {
|
|
2972
|
+
throw new Error("proxy.ts must default-export proxy({ ... }) from @sidecar-ai/server/proxy.");
|
|
2973
|
+
}
|
|
2974
|
+
return proxyValue;
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
function unwrapRuntimeDefault(value) {
|
|
2978
|
+
if (
|
|
2979
|
+
value &&
|
|
2980
|
+
typeof value === "object" &&
|
|
2981
|
+
"default" in value &&
|
|
2982
|
+
Object.keys(value).length === 1
|
|
2983
|
+
) {
|
|
2984
|
+
return unwrapRuntimeDefault(value.default);
|
|
2985
|
+
}
|
|
2986
|
+
return value;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
function readWidget(outputFile) {
|
|
2990
|
+
return readFileSync(new URL(\`../\${outputFile}\`, import.meta.url), "utf8");
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
function readPort() {
|
|
2994
|
+
const raw = process.env.PORT ?? process.env.SIDECAR_PORT ?? "3001";
|
|
2995
|
+
const port = Number(raw);
|
|
2996
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
2997
|
+
throw new Error(\`Invalid PORT/SIDECAR_PORT value: \${raw}\`);
|
|
2998
|
+
}
|
|
2999
|
+
return port;
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
function isDirectRun() {
|
|
3003
|
+
const entry = process.argv[1];
|
|
3004
|
+
if (!entry) {
|
|
3005
|
+
return false;
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
return import.meta.url === pathToFileURL(realpathSync(entry)).href;
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
function shutdown() {
|
|
3012
|
+
server.close(() => process.exit(0));
|
|
3013
|
+
}
|
|
3014
|
+
`;
|
|
3015
|
+
}
|
|
3016
|
+
function renderWidgetResources(manifest) {
|
|
3017
|
+
return manifest.tools.filter((entry) => entry.widget?.outputFile).map((entry) => ` {
|
|
3018
|
+
uri: ${JSON.stringify(entry.widget?.resourceUri)},
|
|
3019
|
+
name: ${JSON.stringify(entry.name)},
|
|
3020
|
+
description: ${JSON.stringify(entry.widget?.options?.description)},
|
|
3021
|
+
mimeType: "text/html;profile=mcp-app",
|
|
3022
|
+
text: readWidget(${JSON.stringify(entry.widget?.outputFile)}),
|
|
3023
|
+
_meta: ${JSON.stringify(entry.widget?.resourceMeta ?? void 0)},
|
|
3024
|
+
},`).join("\n");
|
|
3025
|
+
}
|
|
3026
|
+
function renderServerPackage(identity) {
|
|
3027
|
+
return `${JSON.stringify({
|
|
3028
|
+
name: `${identity.slug}-sidecar-server`,
|
|
3029
|
+
version: identity.version,
|
|
3030
|
+
private: true,
|
|
3031
|
+
type: "module",
|
|
3032
|
+
scripts: {
|
|
3033
|
+
start: "node server/index.js"
|
|
3034
|
+
},
|
|
3035
|
+
engines: {
|
|
3036
|
+
node: ">=20"
|
|
3037
|
+
}
|
|
3038
|
+
}, null, 2)}
|
|
3039
|
+
`;
|
|
3040
|
+
}
|
|
3041
|
+
function renderVercelEntrypoint() {
|
|
3042
|
+
return `export { default } from "../server/index.js";
|
|
3043
|
+
`;
|
|
3044
|
+
}
|
|
3045
|
+
function renderVercelConfig() {
|
|
3046
|
+
return `${JSON.stringify({
|
|
3047
|
+
rewrites: [
|
|
3048
|
+
{
|
|
3049
|
+
source: "/(.*)",
|
|
3050
|
+
destination: "/api/sidecar"
|
|
3051
|
+
}
|
|
3052
|
+
],
|
|
3053
|
+
functions: {
|
|
3054
|
+
"api/sidecar.js": {
|
|
3055
|
+
includeFiles: "public/**",
|
|
3056
|
+
maxDuration: 300
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
}, null, 2)}
|
|
3060
|
+
`;
|
|
3061
|
+
}
|
|
3062
|
+
function sidecarBundleAliases(rootDir) {
|
|
3063
|
+
const repoRoot = findSidecarRepoRoot2(rootDir) ?? findSidecarRepoRoot2(process.cwd());
|
|
3064
|
+
if (!repoRoot) {
|
|
3065
|
+
return void 0;
|
|
3066
|
+
}
|
|
3067
|
+
return {
|
|
3068
|
+
"sidecar-ai": path17.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
3069
|
+
"@sidecar-ai/auth": path17.join(repoRoot, "packages", "auth", "src", "index.ts"),
|
|
3070
|
+
"@sidecar-ai/core": path17.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
3071
|
+
"@sidecar-ai/server": path17.join(repoRoot, "packages", "server", "src", "index.ts"),
|
|
3072
|
+
"@sidecar-ai/server/proxy": path17.join(repoRoot, "packages", "server", "src", "proxy.ts"),
|
|
3073
|
+
"@sidecar-ai/client": path17.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
3074
|
+
"@sidecar-ai/react": path17.join(repoRoot, "packages", "react", "src", "index.ts"),
|
|
3075
|
+
"@sidecar-ai/native": path17.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
3076
|
+
"@sidecar-ai/native/components": path17.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
3077
|
+
"@sidecar-ai/openai": path17.join(repoRoot, "packages", "openai", "src", "index.ts"),
|
|
3078
|
+
"@sidecar-ai/openai/components": path17.join(repoRoot, "packages", "openai", "src", "components.tsx"),
|
|
3079
|
+
"@sidecar-ai/openai/official": path17.join(repoRoot, "packages", "openai", "src", "official.ts"),
|
|
3080
|
+
"@sidecar-ai/anthropic": path17.join(repoRoot, "packages", "anthropic", "src", "index.ts"),
|
|
3081
|
+
"@sidecar-ai/anthropic/agent": path17.join(repoRoot, "packages", "anthropic", "src", "agent.ts"),
|
|
3082
|
+
"@sidecar-ai/anthropic/command": path17.join(repoRoot, "packages", "anthropic", "src", "command.ts"),
|
|
3083
|
+
"@sidecar-ai/anthropic/components": path17.join(repoRoot, "packages", "anthropic", "src", "components.tsx"),
|
|
3084
|
+
"@sidecar-ai/anthropic/hooks": path17.join(repoRoot, "packages", "anthropic", "src", "hooks.ts"),
|
|
3085
|
+
"@sidecar-ai/anthropic/mcp": path17.join(repoRoot, "packages", "anthropic", "src", "mcp.ts"),
|
|
3086
|
+
"@sidecar-ai/anthropic/plugin": path17.join(repoRoot, "packages", "anthropic", "src", "plugin.ts"),
|
|
3087
|
+
"@sidecar-ai/anthropic/skill": path17.join(repoRoot, "packages", "anthropic", "src", "skill.ts")
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
function findSidecarRepoRoot2(startDir) {
|
|
3091
|
+
let current = path17.resolve(startDir);
|
|
3092
|
+
while (true) {
|
|
3093
|
+
if (existsSync5(path17.join(current, "packages", "core", "src", "index.ts"))) {
|
|
3094
|
+
return current;
|
|
3095
|
+
}
|
|
3096
|
+
const parent = path17.dirname(current);
|
|
3097
|
+
if (parent === current) {
|
|
3098
|
+
return void 0;
|
|
3099
|
+
}
|
|
3100
|
+
current = parent;
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
|
|
2780
3104
|
// packages/compiler/src/build.ts
|
|
2781
3105
|
async function buildProject(options) {
|
|
2782
|
-
const rootDir =
|
|
3106
|
+
const rootDir = path18.resolve(options.rootDir);
|
|
2783
3107
|
const target = options.target ?? "mcp";
|
|
3108
|
+
const host = options.host ?? "node";
|
|
2784
3109
|
const config = analyzeProjectConfig(rootDir);
|
|
2785
3110
|
const tools = await analyzeProjectTools(rootDir, { target });
|
|
2786
3111
|
const resources = await analyzeProjectResources(rootDir);
|
|
2787
3112
|
const resourceTemplates = [];
|
|
2788
3113
|
const prompts = await analyzeProjectPrompts(rootDir);
|
|
3114
|
+
const identity = await loadProjectIdentity(rootDir);
|
|
2789
3115
|
const diagnostics = await collectProjectDiagnostics(rootDir, {
|
|
2790
3116
|
tools,
|
|
2791
3117
|
resources,
|
|
@@ -2801,6 +3127,7 @@ async function buildProject(options) {
|
|
|
2801
3127
|
const manifest = {
|
|
2802
3128
|
version: 1,
|
|
2803
3129
|
target,
|
|
3130
|
+
host,
|
|
2804
3131
|
rootDir: ".",
|
|
2805
3132
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2806
3133
|
config,
|
|
@@ -2810,23 +3137,24 @@ async function buildProject(options) {
|
|
|
2810
3137
|
prompts,
|
|
2811
3138
|
diagnostics
|
|
2812
3139
|
};
|
|
2813
|
-
await
|
|
2814
|
-
await
|
|
2815
|
-
|
|
3140
|
+
await mkdir9(outDir, { recursive: true });
|
|
3141
|
+
await writeFile9(
|
|
3142
|
+
path18.join(outDir, "manifest.sidecar.json"),
|
|
2816
3143
|
`${JSON.stringify(manifest, null, 2)}
|
|
2817
3144
|
`
|
|
2818
3145
|
);
|
|
2819
|
-
await
|
|
3146
|
+
await writeFile9(path18.join(outDir, "README.md"), renderMcpReadme(manifest));
|
|
2820
3147
|
await writeGeneratedTypes(rootDir, tools);
|
|
3148
|
+
await buildServerOutput(rootDir, outDir, manifest, identity, host);
|
|
2821
3149
|
if (options.plugins) {
|
|
2822
|
-
await buildPluginPackages(rootDir,
|
|
3150
|
+
await buildPluginPackages(rootDir, path18.dirname(outDir), manifest);
|
|
2823
3151
|
}
|
|
2824
3152
|
return manifest;
|
|
2825
3153
|
}
|
|
2826
3154
|
function resolveInsideRoot(rootDir, output) {
|
|
2827
|
-
const resolved =
|
|
2828
|
-
const relative =
|
|
2829
|
-
if (relative.startsWith("..") ||
|
|
3155
|
+
const resolved = path18.resolve(rootDir, output);
|
|
3156
|
+
const relative = path18.relative(rootDir, resolved);
|
|
3157
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative)) {
|
|
2830
3158
|
throw new Error(`Build output must stay inside the project root: ${output}`);
|
|
2831
3159
|
}
|
|
2832
3160
|
return resolved;
|
|
@@ -2851,13 +3179,41 @@ ${resources || "No resources detected."}
|
|
|
2851
3179
|
|
|
2852
3180
|
${prompts || "No prompts detected."}
|
|
2853
3181
|
|
|
3182
|
+
${manifest.host === "vercel" ? renderVercelReadmeSection() : renderNodeReadmeSection()}
|
|
3183
|
+
|
|
2854
3184
|
## Local HTTPS Testing
|
|
2855
3185
|
|
|
2856
|
-
Run \`sidecar dev --tunnel\` from the project root to start the local MCP server on Streamable HTTP and print
|
|
3186
|
+
Run \`sidecar dev --tunnel\` from the project root to start the local MCP server on Streamable HTTP and print a validated HTTPS MCP URL that can be added to ChatGPT, Claude, or a Claude plugin install. Temporary quick tunnels are public and best-effort; use a configured tunnel/domain or deployed preview for repeatable testing.
|
|
3187
|
+
`;
|
|
3188
|
+
}
|
|
3189
|
+
function renderNodeReadmeSection() {
|
|
3190
|
+
return `## Run The Server
|
|
3191
|
+
|
|
3192
|
+
This output includes a standalone Node MCP server. Start it with:
|
|
3193
|
+
|
|
3194
|
+
\`\`\`sh
|
|
3195
|
+
npm start
|
|
3196
|
+
\`\`\`
|
|
3197
|
+
|
|
3198
|
+
or:
|
|
3199
|
+
|
|
3200
|
+
\`\`\`sh
|
|
3201
|
+
node server/index.js
|
|
3202
|
+
\`\`\`
|
|
3203
|
+
|
|
3204
|
+
Set \`PORT\` or \`SIDECAR_PORT\` to choose the listen port. Hosted/authenticated MCPs should set \`SIDECAR_MCP_URL\` to the public \`https://.../mcp\` URL before starting.
|
|
3205
|
+
`;
|
|
3206
|
+
}
|
|
3207
|
+
function renderVercelReadmeSection() {
|
|
3208
|
+
return `## Deploy To Vercel
|
|
3209
|
+
|
|
3210
|
+
This output includes a Vercel Function shim at \`api/sidecar.js\` and a \`vercel.json\` rewrite that sends Streamable HTTP traffic to \`/mcp\`. Deploy this output directory with Vercel and set \`SIDECAR_MCP_URL\` to the public \`https://.../mcp\` URL.
|
|
2857
3211
|
`;
|
|
2858
3212
|
}
|
|
2859
3213
|
export {
|
|
2860
3214
|
CompilerError,
|
|
3215
|
+
SERVER_ENTRYPOINT,
|
|
3216
|
+
VERCEL_ENTRYPOINT,
|
|
2861
3217
|
analyzeProjectConfig,
|
|
2862
3218
|
analyzeProjectPrompts,
|
|
2863
3219
|
analyzeProjectResources,
|