@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 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
- export { type BuildProjectOptions, CompilerError, type ProjectIdentity, type SidecarCompilerConfig, type SidecarDiagnostic, type SidecarManifest, type SidecarPromptManifestEntry, type SidecarResourceManifestEntry, type SidecarResourceTemplateManifestEntry, type SidecarSourceVariant, type SidecarTarget, type SidecarToolManifestEntry, type SidecarWidgetManifestEntry, analyzeProjectConfig, analyzeProjectPrompts, analyzeProjectResources, analyzeProjectTools, analyzePromptFile, analyzeResourceFile, analyzeToolFile, buildProject, collectProjectDiagnostics, formatDiagnostic };
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.csp?.resourceDomains ? [...options.csp.resourceDomains] : [],
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 mkdir8, writeFile as writeFile8 } from "fs/promises";
1464
- import path17 from "path";
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 printed HTTPS MCP URL.
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 = path17.resolve(options.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 mkdir8(outDir, { recursive: true });
2814
- await writeFile8(
2815
- path17.join(outDir, "manifest.sidecar.json"),
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 writeFile8(path17.join(outDir, "README.md"), renderMcpReadme(manifest));
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, path17.dirname(outDir), manifest);
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 = path17.resolve(rootDir, output);
2828
- const relative = path17.relative(rootDir, resolved);
2829
- if (relative.startsWith("..") || path17.isAbsolute(relative)) {
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 an HTTPS MCP URL that can be added to ChatGPT, Claude, or a Claude plugin install.
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,