@sidecar-ai/cli 0.1.0-alpha.10 → 0.1.0-alpha.5
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.js +384 -778
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// packages/cli/src/index.ts
|
|
4
|
-
import { existsSync as
|
|
4
|
+
import { existsSync as existsSync6, realpathSync } from "fs";
|
|
5
5
|
import { mkdir as mkdir10, readFile as readFile8, writeFile as writeFile10 } from "fs/promises";
|
|
6
6
|
import { createServer as createServer2 } from "http";
|
|
7
|
-
import
|
|
7
|
+
import path19 from "path";
|
|
8
8
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
9
|
-
import { fileURLToPath, pathToFileURL
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
10
10
|
import { cwd, exit, stdin as stdin2, stdout as stdout2 } from "process";
|
|
11
|
-
import { tsImport
|
|
11
|
+
import { tsImport } from "tsx/esm/api";
|
|
12
12
|
|
|
13
13
|
// packages/auth/src/core.ts
|
|
14
14
|
var authBrand = /* @__PURE__ */ Symbol.for("sidecar.auth");
|
|
@@ -66,9 +66,9 @@ var resourceResult = Object.assign(
|
|
|
66
66
|
);
|
|
67
67
|
function createToolResult(input) {
|
|
68
68
|
const resultEnvelope = stripUndefined({
|
|
69
|
-
structuredContent:
|
|
69
|
+
structuredContent: input.structuredContent,
|
|
70
70
|
content: normalizeRequiredContent(input.content),
|
|
71
|
-
_meta:
|
|
71
|
+
_meta: input.meta,
|
|
72
72
|
isError: input.isError
|
|
73
73
|
});
|
|
74
74
|
Object.defineProperty(resultEnvelope, toolResultBrand, {
|
|
@@ -112,9 +112,9 @@ function normalizeToolResult(value) {
|
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
return stripUndefined({
|
|
115
|
-
structuredContent:
|
|
115
|
+
structuredContent: value.structuredContent,
|
|
116
116
|
content: value.content ?? [],
|
|
117
|
-
_meta:
|
|
117
|
+
_meta: value._meta,
|
|
118
118
|
isError: value.isError
|
|
119
119
|
});
|
|
120
120
|
}
|
|
@@ -453,24 +453,10 @@ function normalizePromptResult(value, defaultDescription) {
|
|
|
453
453
|
function stripUndefined(value) {
|
|
454
454
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
455
455
|
}
|
|
456
|
-
function stripJsonUndefined(value) {
|
|
457
|
-
if (value === void 0) {
|
|
458
|
-
return void 0;
|
|
459
|
-
}
|
|
460
|
-
if (Array.isArray(value)) {
|
|
461
|
-
return value.map((entry) => stripJsonUndefined(entry)).filter((entry) => entry !== void 0);
|
|
462
|
-
}
|
|
463
|
-
if (!value || typeof value !== "object") {
|
|
464
|
-
return value;
|
|
465
|
-
}
|
|
466
|
-
return Object.fromEntries(
|
|
467
|
-
Object.entries(value).map(([key, entry]) => [key, stripJsonUndefined(entry)]).filter(([, entry]) => entry !== void 0)
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
456
|
|
|
471
457
|
// packages/compiler/src/analyze.ts
|
|
472
458
|
import { readdir } from "fs/promises";
|
|
473
|
-
import
|
|
459
|
+
import path4 from "path";
|
|
474
460
|
import {
|
|
475
461
|
Node as Node4,
|
|
476
462
|
SyntaxKind as SyntaxKind2
|
|
@@ -637,7 +623,14 @@ function devSidecarTypePaths() {
|
|
|
637
623
|
import {
|
|
638
624
|
Node as Node2
|
|
639
625
|
} from "ts-morph";
|
|
640
|
-
function getParamsSchema(
|
|
626
|
+
function getParamsSchema(definition, execute) {
|
|
627
|
+
const explicitParams = definition.getProperty("params");
|
|
628
|
+
if (explicitParams && Node2.isPropertyAssignment(explicitParams)) {
|
|
629
|
+
const inferred = getSchemaFromZodProperty(explicitParams);
|
|
630
|
+
if (inferred) {
|
|
631
|
+
return inferred;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
641
634
|
const [params] = execute.getParameters();
|
|
642
635
|
if (!params) {
|
|
643
636
|
return emptyObjectSchema();
|
|
@@ -658,6 +651,74 @@ function getOutputSchema(definition, execute) {
|
|
|
658
651
|
}
|
|
659
652
|
return typeToJsonSchema(returnType);
|
|
660
653
|
}
|
|
654
|
+
function getSchemaFromZodProperty(property) {
|
|
655
|
+
const initializer = property.getInitializer();
|
|
656
|
+
if (!initializer) {
|
|
657
|
+
return void 0;
|
|
658
|
+
}
|
|
659
|
+
if (Node2.isCallExpression(initializer) && initializer.getExpression().getText().endsWith(".object")) {
|
|
660
|
+
const [shape] = initializer.getArguments();
|
|
661
|
+
if (shape && Node2.isObjectLiteralExpression(shape)) {
|
|
662
|
+
return zodObjectLiteralToSchema(shape);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return void 0;
|
|
666
|
+
}
|
|
667
|
+
function zodObjectLiteralToSchema(shape) {
|
|
668
|
+
const properties = {};
|
|
669
|
+
const required = [];
|
|
670
|
+
for (const property of shape.getProperties()) {
|
|
671
|
+
if (!Node2.isPropertyAssignment(property)) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
const name = property.getName().replace(/^["']|["']$/g, "");
|
|
675
|
+
const initializer = property.getInitializer();
|
|
676
|
+
if (!initializer) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
const propertySchema = zodExpressionToSchema(initializer);
|
|
680
|
+
properties[name] = propertySchema.schema;
|
|
681
|
+
if (!propertySchema.optional) {
|
|
682
|
+
required.push(name);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return {
|
|
686
|
+
type: "object",
|
|
687
|
+
properties,
|
|
688
|
+
required,
|
|
689
|
+
additionalProperties: false
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function zodExpressionToSchema(expression) {
|
|
693
|
+
const text = expression.getText();
|
|
694
|
+
const optional = /\.optional\(\)/.test(text) || /\.default\(/.test(text);
|
|
695
|
+
const schema = {};
|
|
696
|
+
if (/z\.string\(\)/.test(text)) {
|
|
697
|
+
schema.type = "string";
|
|
698
|
+
} else if (/z\.number\(\)/.test(text)) {
|
|
699
|
+
schema.type = "number";
|
|
700
|
+
} else if (/z\.boolean\(\)/.test(text)) {
|
|
701
|
+
schema.type = "boolean";
|
|
702
|
+
} else if (/z\.array\(/.test(text)) {
|
|
703
|
+
schema.type = "array";
|
|
704
|
+
schema.items = {};
|
|
705
|
+
} else {
|
|
706
|
+
schema.type = "object";
|
|
707
|
+
}
|
|
708
|
+
const min = text.match(/\.min\((\d+)/);
|
|
709
|
+
const max = text.match(/\.max\((\d+)/);
|
|
710
|
+
if (schema.type === "string") {
|
|
711
|
+
if (min) schema.minLength = Number(min[1]);
|
|
712
|
+
if (max) schema.maxLength = Number(max[1]);
|
|
713
|
+
} else {
|
|
714
|
+
if (min) schema.minimum = Number(min[1]);
|
|
715
|
+
if (max) schema.maximum = Number(max[1]);
|
|
716
|
+
}
|
|
717
|
+
if (/\.int\(\)/.test(text)) {
|
|
718
|
+
schema.type = "integer";
|
|
719
|
+
}
|
|
720
|
+
return { schema, optional };
|
|
721
|
+
}
|
|
661
722
|
function typeToJsonSchema(type, description) {
|
|
662
723
|
const withoutUndefined = removeUndefined(type);
|
|
663
724
|
const schema = typeToJsonSchemaInner(withoutUndefined);
|
|
@@ -803,103 +864,11 @@ function schemaDescription(symbol) {
|
|
|
803
864
|
}).find((comment) => comment.trim().length > 0);
|
|
804
865
|
}
|
|
805
866
|
|
|
806
|
-
// packages/compiler/src/runtime-schema.ts
|
|
807
|
-
import { existsSync as existsSync2 } from "fs";
|
|
808
|
-
import path3 from "path";
|
|
809
|
-
import { pathToFileURL } from "url";
|
|
810
|
-
import { tsImport } from "tsx/esm/api";
|
|
811
|
-
async function readRuntimeToolInputSchema(rootDir, sourcePath) {
|
|
812
|
-
let sidecarTool;
|
|
813
|
-
try {
|
|
814
|
-
sidecarTool = await importRuntimeTool(rootDir, sourcePath);
|
|
815
|
-
} catch (error) {
|
|
816
|
-
warnRuntimeSchemaFallback(sourcePath, error);
|
|
817
|
-
return void 0;
|
|
818
|
-
}
|
|
819
|
-
if (!sidecarTool.params) {
|
|
820
|
-
return void 0;
|
|
821
|
-
}
|
|
822
|
-
try {
|
|
823
|
-
return await paramsToJsonSchema(sidecarTool.params);
|
|
824
|
-
} catch (error) {
|
|
825
|
-
warnRuntimeSchemaFallback(sourcePath, error);
|
|
826
|
-
return void 0;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
async function importRuntimeTool(rootDir, sourcePath) {
|
|
830
|
-
const module = await tsImport(pathToFileURL(sourcePath).href, {
|
|
831
|
-
parentURL: runtimeParentUrl(rootDir),
|
|
832
|
-
tsconfig: runtimeTsconfig(rootDir)
|
|
833
|
-
});
|
|
834
|
-
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
835
|
-
if (!isSidecarTool(defaultExport)) {
|
|
836
|
-
throw new Error(`${path3.relative(rootDir, sourcePath)} must default-export tool({ ... }).`);
|
|
837
|
-
}
|
|
838
|
-
return defaultExport;
|
|
839
|
-
}
|
|
840
|
-
async function paramsToJsonSchema(params) {
|
|
841
|
-
const instanceConverter = readInstanceConverter(params);
|
|
842
|
-
if (instanceConverter) {
|
|
843
|
-
return ensureJsonSchema(instanceConverter({ io: "input" }));
|
|
844
|
-
}
|
|
845
|
-
if (isZodMiniSchema(params)) {
|
|
846
|
-
const zod = await import("zod/v4-mini");
|
|
847
|
-
if (typeof zod.toJSONSchema === "function") {
|
|
848
|
-
return ensureJsonSchema(zod.toJSONSchema(params, { io: "input" }));
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
return void 0;
|
|
852
|
-
}
|
|
853
|
-
function readInstanceConverter(params) {
|
|
854
|
-
if (!params || typeof params !== "object") {
|
|
855
|
-
return void 0;
|
|
856
|
-
}
|
|
857
|
-
const record = params;
|
|
858
|
-
const converter = record.toJSONSchema ?? record.toJsonSchema;
|
|
859
|
-
return typeof converter === "function" ? converter.bind(params) : void 0;
|
|
860
|
-
}
|
|
861
|
-
function isZodMiniSchema(params) {
|
|
862
|
-
return Boolean(params && typeof params === "object" && "_zod" in params);
|
|
863
|
-
}
|
|
864
|
-
function ensureJsonSchema(value) {
|
|
865
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
866
|
-
return void 0;
|
|
867
|
-
}
|
|
868
|
-
return value;
|
|
869
|
-
}
|
|
870
|
-
function runtimeParentUrl(rootDir) {
|
|
871
|
-
const configPath = path3.join(rootDir, "sidecar.config.ts");
|
|
872
|
-
return pathToFileURL(existsSync2(configPath) ? configPath : rootDir).href;
|
|
873
|
-
}
|
|
874
|
-
function runtimeTsconfig(rootDir) {
|
|
875
|
-
const projectTsconfig = path3.join(rootDir, "tsconfig.json");
|
|
876
|
-
if (existsSync2(projectTsconfig)) {
|
|
877
|
-
return projectTsconfig;
|
|
878
|
-
}
|
|
879
|
-
const repoTsconfig = path3.join(process.cwd(), "tsconfig.json");
|
|
880
|
-
const repoCore = path3.join(process.cwd(), "packages", "core", "src", "index.ts");
|
|
881
|
-
return existsSyncSafe(repoTsconfig) && existsSyncSafe(repoCore) ? repoTsconfig : false;
|
|
882
|
-
}
|
|
883
|
-
function unwrapRuntimeDefault(value) {
|
|
884
|
-
if (value && typeof value === "object" && "default" in value && Object.keys(value).every((key) => key === "default" || key === "__esModule")) {
|
|
885
|
-
return unwrapRuntimeDefault(value.default);
|
|
886
|
-
}
|
|
887
|
-
return value;
|
|
888
|
-
}
|
|
889
|
-
function warnRuntimeSchemaFallback(sourcePath, error) {
|
|
890
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
891
|
-
console.warn(
|
|
892
|
-
`[sidecar] Could not convert runtime params schema for ${sourcePath}; falling back to TypeScript parameter inference. ${message}`
|
|
893
|
-
);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
867
|
// packages/compiler/src/widgets.ts
|
|
897
868
|
import { createHash } from "crypto";
|
|
898
|
-
import { existsSync as
|
|
869
|
+
import { existsSync as existsSync2 } from "fs";
|
|
899
870
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
900
|
-
import
|
|
901
|
-
import path4 from "path";
|
|
902
|
-
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
871
|
+
import path3 from "path";
|
|
903
872
|
import { build as esbuild } from "esbuild";
|
|
904
873
|
import postcss from "postcss";
|
|
905
874
|
import {
|
|
@@ -907,30 +876,28 @@ import {
|
|
|
907
876
|
SyntaxKind
|
|
908
877
|
} from "ts-morph";
|
|
909
878
|
var CLAUDE_FONT_RESOURCE_DOMAIN = "https://assets.claude.ai";
|
|
910
|
-
|
|
911
|
-
async function buildWidgets(rootDir, outDir, tools, config = void 0) {
|
|
879
|
+
async function buildWidgets(rootDir, outDir, tools) {
|
|
912
880
|
const widgets = tools.filter(
|
|
913
881
|
(entry) => Boolean(entry.widget)
|
|
914
882
|
);
|
|
915
883
|
if (!widgets.length) {
|
|
916
884
|
return;
|
|
917
885
|
}
|
|
918
|
-
const cacheDir =
|
|
886
|
+
const cacheDir = path3.join(rootDir, ".sidecar", "cache", "widgets");
|
|
919
887
|
await mkdir(cacheDir, { recursive: true });
|
|
920
888
|
const appStyle = await prepareAppStyle(rootDir, cacheDir);
|
|
921
|
-
const configure = await loadWidgetBundlerHook(rootDir, cacheDir, config?.configure);
|
|
922
889
|
for (const entry of widgets) {
|
|
923
|
-
const sourceFile =
|
|
890
|
+
const sourceFile = path3.join(rootDir, entry.widget.sourceFile);
|
|
924
891
|
const safeId = safePathSegment(entry.id);
|
|
925
|
-
const entryFile =
|
|
926
|
-
const importPath = toImportSpecifier(
|
|
892
|
+
const entryFile = path3.join(cacheDir, `${safeId}.entry.tsx`);
|
|
893
|
+
const importPath = toImportSpecifier(path3.dirname(entryFile), sourceFile);
|
|
927
894
|
await writeFile(
|
|
928
895
|
entryFile,
|
|
929
896
|
`import React from "react";
|
|
930
897
|
import { createRoot } from "react-dom/client";
|
|
931
898
|
import { SidecarWidgetRoot } from "@sidecar-ai/react";
|
|
932
899
|
import "@sidecar-ai/native/styles.css";
|
|
933
|
-
${appStyle ? `import ${JSON.stringify(toImportSpecifier(
|
|
900
|
+
${appStyle ? `import ${JSON.stringify(toImportSpecifier(path3.dirname(entryFile), appStyle))};` : ""}
|
|
934
901
|
import Component from ${JSON.stringify(importPath)};
|
|
935
902
|
|
|
936
903
|
createRoot(document.getElementById("root")!).render(
|
|
@@ -938,219 +905,64 @@ createRoot(document.getElementById("root")!).render(
|
|
|
938
905
|
);
|
|
939
906
|
`
|
|
940
907
|
);
|
|
941
|
-
const
|
|
908
|
+
const bundled = await esbuild({
|
|
942
909
|
absWorkingDir: rootDir,
|
|
943
|
-
alias:
|
|
910
|
+
alias: devSidecarBundleAliases(rootDir),
|
|
944
911
|
bundle: true,
|
|
945
|
-
define: {
|
|
946
|
-
"process.env.NODE_ENV": JSON.stringify("production")
|
|
947
|
-
},
|
|
948
912
|
entryPoints: [entryFile],
|
|
949
913
|
format: "iife",
|
|
950
914
|
jsx: "automatic",
|
|
951
|
-
minify:
|
|
915
|
+
minify: false,
|
|
952
916
|
nodePaths: [
|
|
953
|
-
|
|
954
|
-
|
|
917
|
+
path3.join(rootDir, "node_modules"),
|
|
918
|
+
path3.join(process.cwd(), "node_modules")
|
|
955
919
|
],
|
|
956
920
|
outfile: "widget.js",
|
|
957
921
|
platform: "browser",
|
|
958
922
|
sourcemap: false,
|
|
959
923
|
write: false
|
|
960
924
|
});
|
|
961
|
-
const
|
|
962
|
-
const
|
|
963
|
-
rootDir,
|
|
964
|
-
outDir,
|
|
965
|
-
entryFile,
|
|
966
|
-
widget: {
|
|
967
|
-
toolId: entry.id,
|
|
968
|
-
toolName: entry.name,
|
|
969
|
-
target: entry.target,
|
|
970
|
-
sourceFile: entry.widget.sourceFile
|
|
971
|
-
},
|
|
972
|
-
esbuildOptions: mergeWidgetBuildOptions(baseOptions, staticOptions)
|
|
973
|
-
}) : void 0;
|
|
974
|
-
const bundled = await esbuild(enforceWidgetBuildInvariants(
|
|
975
|
-
mergeWidgetBuildOptions(baseOptions, staticOptions, configuredOptions),
|
|
976
|
-
{ rootDir, entryFile }
|
|
977
|
-
));
|
|
978
|
-
const outputFiles = bundled.outputFiles ?? [];
|
|
979
|
-
const javascript = outputFiles.find((file) => file.path.endsWith(".js"))?.text ?? "";
|
|
980
|
-
const css = outputFiles.filter((file) => file.path.endsWith(".css")).map((file) => file.text).join("\n");
|
|
925
|
+
const javascript = bundled.outputFiles.find((file) => file.path.endsWith(".js"))?.text ?? "";
|
|
926
|
+
const css = bundled.outputFiles.filter((file) => file.path.endsWith(".css")).map((file) => file.text).join("\n");
|
|
981
927
|
const html = renderWidgetHtml(entry.name, javascript, css);
|
|
982
928
|
const hash = createHash("sha256").update(html).digest("hex").slice(0, 12);
|
|
983
|
-
const outputDir =
|
|
984
|
-
const outputFile =
|
|
929
|
+
const outputDir = path3.join(outDir, "public", "widgets", safeId);
|
|
930
|
+
const outputFile = path3.join(outputDir, `widget.${hash}.html`);
|
|
985
931
|
const resourceUri = `ui://${safeId}/widget.${hash}.html`;
|
|
986
932
|
await mkdir(outputDir, { recursive: true });
|
|
987
933
|
await writeFile(outputFile, html);
|
|
988
934
|
entry.widget.resourceUri = resourceUri;
|
|
989
935
|
entry.widget.resourceMeta = widgetResourceMeta(entry.widget.options, entry.target);
|
|
990
|
-
entry.widget.outputFile =
|
|
936
|
+
entry.widget.outputFile = path3.relative(outDir, outputFile);
|
|
991
937
|
entry.descriptor._meta = mergeWidgetMeta(entry.descriptor._meta, widgetMeta(resourceUri, entry.widget.options, entry.target));
|
|
992
938
|
}
|
|
993
939
|
}
|
|
994
|
-
function widgetBuildOptionsFromConfig(rootDir, config) {
|
|
995
|
-
const esbuildConfig = config?.esbuild;
|
|
996
|
-
if (!esbuildConfig) {
|
|
997
|
-
return void 0;
|
|
998
|
-
}
|
|
999
|
-
return {
|
|
1000
|
-
alias: normalizeAliases(rootDir, esbuildConfig.alias),
|
|
1001
|
-
conditions: esbuildConfig.conditions,
|
|
1002
|
-
define: esbuildConfig.define,
|
|
1003
|
-
external: esbuildConfig.external,
|
|
1004
|
-
jsx: esbuildConfig.jsx,
|
|
1005
|
-
jsxImportSource: esbuildConfig.jsxImportSource,
|
|
1006
|
-
loader: esbuildConfig.loader,
|
|
1007
|
-
mainFields: esbuildConfig.mainFields
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
async function loadWidgetBundlerHook(rootDir, cacheDir, hookPath) {
|
|
1011
|
-
if (!hookPath) {
|
|
1012
|
-
return void 0;
|
|
1013
|
-
}
|
|
1014
|
-
const sourcePath = path4.resolve(rootDir, hookPath);
|
|
1015
|
-
const relative = path4.relative(rootDir, sourcePath);
|
|
1016
|
-
if (relative.startsWith("..") || path4.isAbsolute(relative)) {
|
|
1017
|
-
throw new Error(`Widget bundler hook must stay inside the project root: ${hookPath}`);
|
|
1018
|
-
}
|
|
1019
|
-
if (!existsSync3(sourcePath)) {
|
|
1020
|
-
throw new Error(`Widget bundler hook not found: ${hookPath}`);
|
|
1021
|
-
}
|
|
1022
|
-
const outputFile = path4.join(cacheDir, `widget-bundler.${contentHash(hookPath)}.mjs`);
|
|
1023
|
-
await esbuild({
|
|
1024
|
-
absWorkingDir: rootDir,
|
|
1025
|
-
alias: devSidecarBundleAliases(rootDir),
|
|
1026
|
-
bundle: true,
|
|
1027
|
-
entryPoints: [sourcePath],
|
|
1028
|
-
format: "esm",
|
|
1029
|
-
nodePaths: [
|
|
1030
|
-
path4.join(rootDir, "node_modules"),
|
|
1031
|
-
path4.join(process.cwd(), "node_modules")
|
|
1032
|
-
],
|
|
1033
|
-
outfile: outputFile,
|
|
1034
|
-
packages: "external",
|
|
1035
|
-
platform: "node",
|
|
1036
|
-
target: "node20"
|
|
1037
|
-
});
|
|
1038
|
-
const module = await import(`${pathToFileURL2(outputFile).href}?t=${Date.now()}`);
|
|
1039
|
-
if (typeof module.default !== "function") {
|
|
1040
|
-
throw new Error(`Widget bundler hook must default-export a function: ${hookPath}`);
|
|
1041
|
-
}
|
|
1042
|
-
return module.default;
|
|
1043
|
-
}
|
|
1044
|
-
async function configureWidgetBuild(hook, input) {
|
|
1045
|
-
const result = await hook(input);
|
|
1046
|
-
if (!result) {
|
|
1047
|
-
return void 0;
|
|
1048
|
-
}
|
|
1049
|
-
if (typeof result === "object" && "esbuildOptions" in result) {
|
|
1050
|
-
return result.esbuildOptions;
|
|
1051
|
-
}
|
|
1052
|
-
return result;
|
|
1053
|
-
}
|
|
1054
|
-
function mergeWidgetBuildOptions(...options) {
|
|
1055
|
-
const merged = {};
|
|
1056
|
-
for (const option of options) {
|
|
1057
|
-
if (!option) {
|
|
1058
|
-
continue;
|
|
1059
|
-
}
|
|
1060
|
-
const previousAlias = merged.alias;
|
|
1061
|
-
const previousDefine = merged.define;
|
|
1062
|
-
const previousLoader = merged.loader;
|
|
1063
|
-
const previousExternal = merged.external;
|
|
1064
|
-
const previousNodePaths = merged.nodePaths;
|
|
1065
|
-
const previousPlugins = merged.plugins;
|
|
1066
|
-
Object.assign(merged, option);
|
|
1067
|
-
merged.alias = { ...previousAlias ?? {}, ...option.alias ?? {} };
|
|
1068
|
-
merged.define = { ...previousDefine ?? {}, ...option.define ?? {} };
|
|
1069
|
-
merged.loader = { ...previousLoader ?? {}, ...option.loader ?? {} };
|
|
1070
|
-
merged.external = uniqueStrings([...previousExternal ?? [], ...option.external ?? []]);
|
|
1071
|
-
merged.nodePaths = uniqueStrings([...previousNodePaths ?? [], ...option.nodePaths ?? []]);
|
|
1072
|
-
merged.plugins = [...previousPlugins ?? [], ...option.plugins ?? []];
|
|
1073
|
-
}
|
|
1074
|
-
return merged;
|
|
1075
|
-
}
|
|
1076
|
-
function enforceWidgetBuildInvariants(options, required) {
|
|
1077
|
-
const aliases = required ? { ...options.alias ?? {}, ...reactSingletonAliases(required.rootDir) } : options.alias;
|
|
1078
|
-
return {
|
|
1079
|
-
...options,
|
|
1080
|
-
absWorkingDir: required?.rootDir ?? options.absWorkingDir,
|
|
1081
|
-
alias: aliases,
|
|
1082
|
-
bundle: true,
|
|
1083
|
-
entryPoints: required ? [required.entryFile] : options.entryPoints,
|
|
1084
|
-
format: "iife",
|
|
1085
|
-
outfile: "widget.js",
|
|
1086
|
-
platform: "browser",
|
|
1087
|
-
write: false
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
function sidecarWidgetAliases(rootDir) {
|
|
1091
|
-
return {
|
|
1092
|
-
...devSidecarBundleAliases(rootDir) ?? {},
|
|
1093
|
-
...reactSingletonAliases(rootDir)
|
|
1094
|
-
};
|
|
1095
|
-
}
|
|
1096
|
-
function reactSingletonAliases(rootDir) {
|
|
1097
|
-
return {
|
|
1098
|
-
react: resolveProjectModule(rootDir, "react"),
|
|
1099
|
-
"react/jsx-runtime": resolveProjectModule(rootDir, "react/jsx-runtime"),
|
|
1100
|
-
"react/jsx-dev-runtime": resolveProjectModule(rootDir, "react/jsx-dev-runtime"),
|
|
1101
|
-
"react-dom": resolveProjectModule(rootDir, "react-dom"),
|
|
1102
|
-
"react-dom/client": resolveProjectModule(rootDir, "react-dom/client"),
|
|
1103
|
-
"react-dom/server": resolveProjectModule(rootDir, "react-dom/server")
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
function resolveProjectModule(rootDir, specifier) {
|
|
1107
|
-
return requireFromCompiler.resolve(specifier, {
|
|
1108
|
-
paths: [rootDir, process.cwd()]
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
|
-
function normalizeAliases(rootDir, aliases) {
|
|
1112
|
-
if (!aliases) {
|
|
1113
|
-
return void 0;
|
|
1114
|
-
}
|
|
1115
|
-
return Object.fromEntries(
|
|
1116
|
-
Object.entries(aliases).map(([key, value]) => [
|
|
1117
|
-
key,
|
|
1118
|
-
value.startsWith(".") ? path4.resolve(rootDir, value) : value
|
|
1119
|
-
])
|
|
1120
|
-
);
|
|
1121
|
-
}
|
|
1122
|
-
function uniqueStrings(values) {
|
|
1123
|
-
return [...new Set(values)];
|
|
1124
|
-
}
|
|
1125
|
-
function contentHash(value) {
|
|
1126
|
-
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
1127
|
-
}
|
|
1128
940
|
function devSidecarBundleAliases(rootDir) {
|
|
1129
941
|
const repoRoot = findSidecarRepoRoot(rootDir) ?? findSidecarRepoRoot(process.cwd());
|
|
1130
942
|
if (!repoRoot) {
|
|
1131
943
|
return void 0;
|
|
1132
944
|
}
|
|
1133
|
-
const reactEntry =
|
|
1134
|
-
if (!
|
|
945
|
+
const reactEntry = path3.join(repoRoot, "packages", "react", "src", "index.ts");
|
|
946
|
+
if (!existsSync2(reactEntry)) {
|
|
1135
947
|
return void 0;
|
|
1136
948
|
}
|
|
1137
949
|
return {
|
|
1138
|
-
"sidecar-ai":
|
|
1139
|
-
"@sidecar-ai/client":
|
|
1140
|
-
"@sidecar-ai/core":
|
|
950
|
+
"sidecar-ai": path3.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
951
|
+
"@sidecar-ai/client": path3.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
952
|
+
"@sidecar-ai/core": path3.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
1141
953
|
"@sidecar-ai/react": reactEntry,
|
|
1142
|
-
"@sidecar-ai/native":
|
|
1143
|
-
"@sidecar-ai/native/components":
|
|
1144
|
-
"@sidecar-ai/native/styles.css":
|
|
954
|
+
"@sidecar-ai/native": path3.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
955
|
+
"@sidecar-ai/native/components": path3.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
956
|
+
"@sidecar-ai/native/styles.css": path3.join(repoRoot, "packages", "native", "src", "styles.css")
|
|
1145
957
|
};
|
|
1146
958
|
}
|
|
1147
959
|
function findSidecarRepoRoot(startDir) {
|
|
1148
|
-
let current =
|
|
960
|
+
let current = path3.resolve(startDir);
|
|
1149
961
|
while (true) {
|
|
1150
|
-
if (
|
|
962
|
+
if (existsSync2(path3.join(current, "packages", "core", "src", "index.ts"))) {
|
|
1151
963
|
return current;
|
|
1152
964
|
}
|
|
1153
|
-
const parent =
|
|
965
|
+
const parent = path3.dirname(current);
|
|
1154
966
|
if (parent === current) {
|
|
1155
967
|
return void 0;
|
|
1156
968
|
}
|
|
@@ -1158,13 +970,13 @@ function findSidecarRepoRoot(startDir) {
|
|
|
1158
970
|
}
|
|
1159
971
|
}
|
|
1160
972
|
async function prepareAppStyle(rootDir, cacheDir) {
|
|
1161
|
-
const sourceFile =
|
|
1162
|
-
if (!
|
|
973
|
+
const sourceFile = path3.join(rootDir, "style.css");
|
|
974
|
+
if (!existsSync2(sourceFile)) {
|
|
1163
975
|
return void 0;
|
|
1164
976
|
}
|
|
1165
977
|
const source = await readFile(sourceFile, "utf8");
|
|
1166
978
|
const css = await processAppStyle(source, sourceFile);
|
|
1167
|
-
const outputFile =
|
|
979
|
+
const outputFile = path3.join(cacheDir, "style.css");
|
|
1168
980
|
await writeFile(outputFile, css);
|
|
1169
981
|
return outputFile;
|
|
1170
982
|
}
|
|
@@ -1176,7 +988,7 @@ async function processAppStyle(source, from) {
|
|
|
1176
988
|
const plugins = [];
|
|
1177
989
|
if (cssSource.includes("@tailwind")) {
|
|
1178
990
|
const tailwind = await import("@tailwindcss/postcss");
|
|
1179
|
-
plugins.push(tailwind.default({ base:
|
|
991
|
+
plugins.push(tailwind.default({ base: path3.dirname(from) }));
|
|
1180
992
|
}
|
|
1181
993
|
const autoprefixer = await import("autoprefixer");
|
|
1182
994
|
plugins.push(autoprefixer.default());
|
|
@@ -1190,13 +1002,13 @@ function needsPostcss(source) {
|
|
|
1190
1002
|
return /@import\s+["']tailwindcss["']|@tailwind|@source|@theme|@plugin/.test(source);
|
|
1191
1003
|
}
|
|
1192
1004
|
function findWidget(rootDir, toolFile, id, target = "mcp", toolVariant = "shared") {
|
|
1193
|
-
const selected = selectWidgetFile(
|
|
1005
|
+
const selected = selectWidgetFile(path3.dirname(toolFile), target, toolVariant);
|
|
1194
1006
|
if (!selected) {
|
|
1195
1007
|
return void 0;
|
|
1196
1008
|
}
|
|
1197
1009
|
const safeId = safePathSegment(id);
|
|
1198
1010
|
return {
|
|
1199
|
-
sourceFile:
|
|
1011
|
+
sourceFile: path3.relative(rootDir, selected.filePath),
|
|
1200
1012
|
variant: selected.variant,
|
|
1201
1013
|
resourceUri: `ui://${safeId}/widget.html`
|
|
1202
1014
|
};
|
|
@@ -1231,8 +1043,7 @@ function widgetMeta(resourceUri, options = {}, target = "mcp") {
|
|
|
1231
1043
|
const standard = {
|
|
1232
1044
|
ui: {
|
|
1233
1045
|
resourceUri
|
|
1234
|
-
}
|
|
1235
|
-
"ui/resourceUri": resourceUri
|
|
1046
|
+
}
|
|
1236
1047
|
};
|
|
1237
1048
|
if (target !== "chatgpt") {
|
|
1238
1049
|
return standard;
|
|
@@ -1379,17 +1190,17 @@ function readStringArrayProperty(definition, propertyName) {
|
|
|
1379
1190
|
}
|
|
1380
1191
|
function selectWidgetFile(directory, target, toolVariant) {
|
|
1381
1192
|
if (toolVariant === "openai") {
|
|
1382
|
-
const filePath =
|
|
1383
|
-
return
|
|
1193
|
+
const filePath = path3.join(directory, "widget.openai.tsx");
|
|
1194
|
+
return existsSync2(filePath) ? { filePath, variant: "openai" } : void 0;
|
|
1384
1195
|
}
|
|
1385
1196
|
if (toolVariant === "anthropic") {
|
|
1386
|
-
const filePath =
|
|
1387
|
-
return
|
|
1197
|
+
const filePath = path3.join(directory, "widget.anthropic.tsx");
|
|
1198
|
+
return existsSync2(filePath) ? { filePath, variant: "anthropic" } : void 0;
|
|
1388
1199
|
}
|
|
1389
1200
|
const candidates = target === "chatgpt" || target === "claude" || target === "mcp" ? [{ name: "widget.tsx", variant: "shared" }] : [];
|
|
1390
1201
|
for (const candidate of candidates) {
|
|
1391
|
-
const filePath =
|
|
1392
|
-
if (
|
|
1202
|
+
const filePath = path3.join(directory, candidate.name);
|
|
1203
|
+
if (existsSync2(filePath)) {
|
|
1393
1204
|
return { filePath, variant: candidate.variant };
|
|
1394
1205
|
}
|
|
1395
1206
|
}
|
|
@@ -1440,23 +1251,17 @@ function stripUndefined3(value) {
|
|
|
1440
1251
|
// packages/compiler/src/analyze.ts
|
|
1441
1252
|
async function analyzeProjectTools(rootDir, options = {}) {
|
|
1442
1253
|
const target = options.target ?? "mcp";
|
|
1443
|
-
const toolFiles = await findToolFiles(
|
|
1254
|
+
const toolFiles = await findToolFiles(path4.join(rootDir, "server"), target);
|
|
1444
1255
|
if (toolFiles.length === 0) {
|
|
1445
1256
|
return [];
|
|
1446
1257
|
}
|
|
1447
1258
|
const project = createProject(rootDir);
|
|
1448
1259
|
const authScopes = readAuthScopeCatalog(project, rootDir);
|
|
1449
|
-
|
|
1450
|
-
candidate,
|
|
1451
|
-
sourceFile: project.addSourceFileAtPath(candidate.filePath)
|
|
1452
|
-
}));
|
|
1453
|
-
const runtimeInputSchemas = await readRuntimeInputSchemas(rootDir, sources);
|
|
1454
|
-
return sources.map(
|
|
1455
|
-
({ candidate, sourceFile }) => analyzeToolFile(sourceFile, rootDir, {
|
|
1260
|
+
return toolFiles.map(
|
|
1261
|
+
(candidate) => analyzeToolFile(project.addSourceFileAtPath(candidate.filePath), rootDir, {
|
|
1456
1262
|
target,
|
|
1457
1263
|
variant: candidate.variant,
|
|
1458
|
-
authScopes
|
|
1459
|
-
inputSchema: runtimeInputSchemas.get(candidate.filePath)
|
|
1264
|
+
authScopes
|
|
1460
1265
|
})
|
|
1461
1266
|
);
|
|
1462
1267
|
}
|
|
@@ -1465,7 +1270,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1465
1270
|
const variant = options.variant ?? "shared";
|
|
1466
1271
|
const definition = findToolDefinition(sourceFile);
|
|
1467
1272
|
const absoluteFile = sourceFile.getFilePath();
|
|
1468
|
-
const directory =
|
|
1273
|
+
const directory = path4.basename(path4.dirname(absoluteFile));
|
|
1469
1274
|
const name = getRequiredStringProperty(definition, "name", sourceFile);
|
|
1470
1275
|
const id = getOptionalStringProperty(definition, "id") ?? toMachineName(directory);
|
|
1471
1276
|
const description = getRequiredStringProperty(
|
|
@@ -1478,7 +1283,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1478
1283
|
const hosts = readHosts(definition);
|
|
1479
1284
|
const auth = readAuthPolicy(definition, options.authScopes ?? {});
|
|
1480
1285
|
const execute = getExecuteFunction(definition, sourceFile);
|
|
1481
|
-
const inputSchema =
|
|
1286
|
+
const inputSchema = getParamsSchema(definition, execute);
|
|
1482
1287
|
const outputSchema = getOutputSchema(definition, execute);
|
|
1483
1288
|
const descriptor = createToolDescriptor({
|
|
1484
1289
|
name,
|
|
@@ -1496,7 +1301,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1496
1301
|
validateWidgetHierarchy(sourceFile, absoluteFile, target, variant);
|
|
1497
1302
|
const widget = findWidget(rootDir, absoluteFile, id, target, variant);
|
|
1498
1303
|
if (widget) {
|
|
1499
|
-
const widgetFile =
|
|
1304
|
+
const widgetFile = path4.join(rootDir, widget.sourceFile);
|
|
1500
1305
|
const project = sourceFile.getProject();
|
|
1501
1306
|
const widgetSourceFile = project.getSourceFile(widgetFile) ?? project.addSourceFileAtPath(widgetFile);
|
|
1502
1307
|
widget.options = {
|
|
@@ -1507,7 +1312,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1507
1312
|
descriptor._meta = mergeWidgetMeta(descriptor._meta, widgetMeta(widget.resourceUri, widget.options, target));
|
|
1508
1313
|
}
|
|
1509
1314
|
return {
|
|
1510
|
-
sourceFile:
|
|
1315
|
+
sourceFile: path4.relative(rootDir, absoluteFile),
|
|
1511
1316
|
variant,
|
|
1512
1317
|
target,
|
|
1513
1318
|
directory,
|
|
@@ -1522,26 +1327,6 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1522
1327
|
descriptor
|
|
1523
1328
|
};
|
|
1524
1329
|
}
|
|
1525
|
-
async function readRuntimeInputSchemas(rootDir, sources) {
|
|
1526
|
-
const schemas = /* @__PURE__ */ new Map();
|
|
1527
|
-
await Promise.all(sources.map(async ({ candidate, sourceFile }) => {
|
|
1528
|
-
const definition = findToolDefinition(sourceFile);
|
|
1529
|
-
if (!definitionHasRuntimeParams(definition)) {
|
|
1530
|
-
return;
|
|
1531
|
-
}
|
|
1532
|
-
const schema = await readRuntimeToolInputSchema(rootDir, candidate.filePath);
|
|
1533
|
-
if (schema) {
|
|
1534
|
-
schemas.set(candidate.filePath, schema);
|
|
1535
|
-
}
|
|
1536
|
-
}));
|
|
1537
|
-
return schemas;
|
|
1538
|
-
}
|
|
1539
|
-
function definitionHasRuntimeParams(definition) {
|
|
1540
|
-
if (definition.getProperty("params")) {
|
|
1541
|
-
return true;
|
|
1542
|
-
}
|
|
1543
|
-
return Boolean(getWithParamsCall(definition));
|
|
1544
|
-
}
|
|
1545
1330
|
function readAuthPolicy(definition, authScopes) {
|
|
1546
1331
|
const initializer = readObjectProperty2(definition, "auth");
|
|
1547
1332
|
if (!initializer) {
|
|
@@ -1558,7 +1343,7 @@ function readAuthPolicy(definition, authScopes) {
|
|
|
1558
1343
|
return { authenticated: true };
|
|
1559
1344
|
}
|
|
1560
1345
|
function readAuthScopeCatalog(project, rootDir) {
|
|
1561
|
-
const authPath =
|
|
1346
|
+
const authPath = path4.join(rootDir, "auth.ts");
|
|
1562
1347
|
if (!existsSyncSafe(authPath)) {
|
|
1563
1348
|
return {};
|
|
1564
1349
|
}
|
|
@@ -1640,12 +1425,12 @@ function isNamedCall(call, name) {
|
|
|
1640
1425
|
return callee === name || callee.endsWith(`.${name}`);
|
|
1641
1426
|
}
|
|
1642
1427
|
function validateWidgetHierarchy(sourceFile, toolFile, target, variant) {
|
|
1643
|
-
const directory =
|
|
1428
|
+
const directory = path4.dirname(toolFile);
|
|
1644
1429
|
const platformWidget = target === "chatgpt" ? "widget.openai.tsx" : target === "claude" ? "widget.anthropic.tsx" : void 0;
|
|
1645
1430
|
if (!platformWidget || variant !== "shared") {
|
|
1646
1431
|
return;
|
|
1647
1432
|
}
|
|
1648
|
-
if (existsSyncSafe(
|
|
1433
|
+
if (existsSyncSafe(path4.join(directory, platformWidget))) {
|
|
1649
1434
|
const expectedTool = target === "chatgpt" ? "tool.openai.ts" : "tool.anthropic.ts";
|
|
1650
1435
|
throw new CompilerError(
|
|
1651
1436
|
sourceFile,
|
|
@@ -1660,7 +1445,7 @@ async function findToolFiles(serverDir, target) {
|
|
|
1660
1445
|
const entries = await readdir(serverDir, { withFileTypes: true });
|
|
1661
1446
|
const files = [];
|
|
1662
1447
|
for (const entry of entries) {
|
|
1663
|
-
const entryPath =
|
|
1448
|
+
const entryPath = path4.join(serverDir, entry.name);
|
|
1664
1449
|
if (entry.isDirectory()) {
|
|
1665
1450
|
const candidate = selectToolFile(entryPath, target);
|
|
1666
1451
|
if (candidate) {
|
|
@@ -1679,7 +1464,7 @@ function selectToolFile(directory, target) {
|
|
|
1679
1464
|
{ name: "tool.ts", variant: "shared" }
|
|
1680
1465
|
] : [{ name: "tool.ts", variant: "shared" }];
|
|
1681
1466
|
for (const candidate of candidates) {
|
|
1682
|
-
const filePath =
|
|
1467
|
+
const filePath = path4.join(directory, candidate.name);
|
|
1683
1468
|
if (existsSyncSafe(filePath)) {
|
|
1684
1469
|
return { filePath, variant: candidate.variant };
|
|
1685
1470
|
}
|
|
@@ -1715,32 +1500,16 @@ function getExecuteFunction(definition, sourceFile) {
|
|
|
1715
1500
|
return property;
|
|
1716
1501
|
}
|
|
1717
1502
|
if (Node4.isPropertyAssignment(property)) {
|
|
1718
|
-
const initializer =
|
|
1503
|
+
const initializer = property.getInitializer();
|
|
1719
1504
|
if (initializer && (Node4.isArrowFunction(initializer) || Node4.isFunctionExpression(initializer))) {
|
|
1720
1505
|
return initializer;
|
|
1721
1506
|
}
|
|
1722
|
-
const withParamsCall = getWithParamsCall(definition);
|
|
1723
|
-
const wrappedExecute = unwrapExpression(withParamsCall?.getArguments()[1]);
|
|
1724
|
-
if (wrappedExecute && (Node4.isArrowFunction(wrappedExecute) || Node4.isFunctionExpression(wrappedExecute))) {
|
|
1725
|
-
return wrappedExecute;
|
|
1726
|
-
}
|
|
1727
1507
|
}
|
|
1728
1508
|
throw new CompilerError(
|
|
1729
1509
|
sourceFile,
|
|
1730
1510
|
"execute must be a method, function expression, or arrow function."
|
|
1731
1511
|
);
|
|
1732
1512
|
}
|
|
1733
|
-
function getWithParamsCall(definition) {
|
|
1734
|
-
const property = definition.getProperty("execute");
|
|
1735
|
-
if (!property || !Node4.isPropertyAssignment(property)) {
|
|
1736
|
-
return void 0;
|
|
1737
|
-
}
|
|
1738
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1739
|
-
if (!initializer || !Node4.isCallExpression(initializer)) {
|
|
1740
|
-
return void 0;
|
|
1741
|
-
}
|
|
1742
|
-
return isNamedCall(initializer, "withParams") ? initializer : void 0;
|
|
1743
|
-
}
|
|
1744
1513
|
function getRequiredStringProperty(definition, propertyName, sourceFile) {
|
|
1745
1514
|
const value = getOptionalStringProperty(definition, propertyName);
|
|
1746
1515
|
if (value === void 0 || !value.trim()) {
|
|
@@ -1896,16 +1665,16 @@ function readStringArrayProperty2(definition, propertyName) {
|
|
|
1896
1665
|
|
|
1897
1666
|
// packages/compiler/src/build.ts
|
|
1898
1667
|
import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
|
|
1899
|
-
import
|
|
1668
|
+
import path18 from "path";
|
|
1900
1669
|
|
|
1901
1670
|
// packages/compiler/src/config.ts
|
|
1902
|
-
import
|
|
1671
|
+
import path5 from "path";
|
|
1903
1672
|
import {
|
|
1904
1673
|
Node as Node5,
|
|
1905
1674
|
SyntaxKind as SyntaxKind3
|
|
1906
1675
|
} from "ts-morph";
|
|
1907
1676
|
function analyzeProjectConfig(rootDir) {
|
|
1908
|
-
const configPath =
|
|
1677
|
+
const configPath = path5.join(rootDir, "sidecar.config.ts");
|
|
1909
1678
|
if (!existsSyncSafe(configPath)) {
|
|
1910
1679
|
return defaultCompilerConfig();
|
|
1911
1680
|
}
|
|
@@ -1921,8 +1690,7 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1921
1690
|
target: readTargetNested(definition, "build", "target"),
|
|
1922
1691
|
host: readHostNested(definition, "build", "host"),
|
|
1923
1692
|
outDir: readStringNested(definition, "build", "outDir"),
|
|
1924
|
-
plugins: readBooleanNested(definition, "build", "plugins")
|
|
1925
|
-
widgets: readWidgetBuildConfig(definition)
|
|
1693
|
+
plugins: readBooleanNested(definition, "build", "plugins")
|
|
1926
1694
|
},
|
|
1927
1695
|
resources: {
|
|
1928
1696
|
subscribe: readBooleanNested(definition, "resources", "subscribe") ?? false,
|
|
@@ -1935,49 +1703,11 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1935
1703
|
listChanged: readBooleanNested(definition, "tools", "listChanged") ?? false
|
|
1936
1704
|
},
|
|
1937
1705
|
pagination: {
|
|
1938
|
-
pageSize: readNumberNested(definition, "pagination", "pageSize") ??
|
|
1706
|
+
pageSize: readNumberNested(definition, "pagination", "pageSize") ?? 10,
|
|
1939
1707
|
hasOverride: hasProperty(readObjectProperty3(definition, "pagination"), "override")
|
|
1940
1708
|
}
|
|
1941
1709
|
};
|
|
1942
1710
|
}
|
|
1943
|
-
function readWidgetBuildConfig(definition) {
|
|
1944
|
-
const widgets = readObjectProperty3(readObjectProperty3(definition, "build"), "widgets");
|
|
1945
|
-
if (!widgets) {
|
|
1946
|
-
return void 0;
|
|
1947
|
-
}
|
|
1948
|
-
const config = {};
|
|
1949
|
-
const configure = readStringProperty3(widgets, "configure");
|
|
1950
|
-
const esbuild3 = readWidgetEsbuildConfig(widgets);
|
|
1951
|
-
if (configure) config.configure = configure;
|
|
1952
|
-
if (esbuild3) config.esbuild = esbuild3;
|
|
1953
|
-
return Object.keys(config).length ? config : void 0;
|
|
1954
|
-
}
|
|
1955
|
-
function readWidgetEsbuildConfig(widgets) {
|
|
1956
|
-
const esbuild3 = readObjectProperty3(widgets, "esbuild");
|
|
1957
|
-
if (!esbuild3) {
|
|
1958
|
-
return void 0;
|
|
1959
|
-
}
|
|
1960
|
-
const config = {};
|
|
1961
|
-
const alias = readStringRecordProperty(esbuild3, "alias");
|
|
1962
|
-
const define = readStringRecordProperty(esbuild3, "define");
|
|
1963
|
-
const external = readStringArrayProperty3(esbuild3, "external");
|
|
1964
|
-
const loader = readStringRecordProperty(esbuild3, "loader");
|
|
1965
|
-
const conditions = readStringArrayProperty3(esbuild3, "conditions");
|
|
1966
|
-
const mainFields = readStringArrayProperty3(esbuild3, "mainFields");
|
|
1967
|
-
const jsx = readStringProperty3(esbuild3, "jsx");
|
|
1968
|
-
const jsxImportSource = readStringProperty3(esbuild3, "jsxImportSource");
|
|
1969
|
-
if (alias) config.alias = alias;
|
|
1970
|
-
if (define) config.define = define;
|
|
1971
|
-
if (external) config.external = external;
|
|
1972
|
-
if (loader) config.loader = loader;
|
|
1973
|
-
if (conditions) config.conditions = conditions;
|
|
1974
|
-
if (mainFields) config.mainFields = mainFields;
|
|
1975
|
-
if (jsx === "automatic" || jsx === "transform" || jsx === "preserve") {
|
|
1976
|
-
config.jsx = jsx;
|
|
1977
|
-
}
|
|
1978
|
-
if (jsxImportSource) config.jsxImportSource = jsxImportSource;
|
|
1979
|
-
return Object.keys(config).length ? config : void 0;
|
|
1980
|
-
}
|
|
1981
1711
|
function defaultCompilerConfig() {
|
|
1982
1712
|
return {
|
|
1983
1713
|
build: {},
|
|
@@ -1992,7 +1722,7 @@ function defaultCompilerConfig() {
|
|
|
1992
1722
|
listChanged: false
|
|
1993
1723
|
},
|
|
1994
1724
|
pagination: {
|
|
1995
|
-
pageSize:
|
|
1725
|
+
pageSize: 10,
|
|
1996
1726
|
hasOverride: false
|
|
1997
1727
|
}
|
|
1998
1728
|
};
|
|
@@ -2010,7 +1740,12 @@ function readStringNested(definition, section, propertyName) {
|
|
|
2010
1740
|
if (!object) {
|
|
2011
1741
|
return void 0;
|
|
2012
1742
|
}
|
|
2013
|
-
|
|
1743
|
+
const property = object.getProperty(propertyName);
|
|
1744
|
+
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1745
|
+
return void 0;
|
|
1746
|
+
}
|
|
1747
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1748
|
+
return initializer && Node5.isStringLiteral(initializer) ? initializer.getLiteralText() : void 0;
|
|
2014
1749
|
}
|
|
2015
1750
|
function readBooleanNested(definition, section, propertyName) {
|
|
2016
1751
|
const object = readObjectProperty3(definition, section);
|
|
@@ -2042,9 +1777,6 @@ function readNumberNested(definition, section, propertyName) {
|
|
|
2042
1777
|
return initializer && Node5.isNumericLiteral(initializer) ? Number(initializer.getLiteralText()) : void 0;
|
|
2043
1778
|
}
|
|
2044
1779
|
function readObjectProperty3(definition, propertyName) {
|
|
2045
|
-
if (!definition) {
|
|
2046
|
-
return void 0;
|
|
2047
|
-
}
|
|
2048
1780
|
const property = definition.getProperty(propertyName);
|
|
2049
1781
|
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
2050
1782
|
return void 0;
|
|
@@ -2052,79 +1784,38 @@ function readObjectProperty3(definition, propertyName) {
|
|
|
2052
1784
|
const initializer = unwrapExpression(property.getInitializer());
|
|
2053
1785
|
return initializer && Node5.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
2054
1786
|
}
|
|
2055
|
-
function readStringProperty3(definition, propertyName) {
|
|
2056
|
-
const property = definition.getProperty(propertyName);
|
|
2057
|
-
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
2058
|
-
return void 0;
|
|
2059
|
-
}
|
|
2060
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
2061
|
-
return initializer && Node5.isStringLiteral(initializer) ? initializer.getLiteralText() : void 0;
|
|
2062
|
-
}
|
|
2063
|
-
function readStringArrayProperty3(definition, propertyName) {
|
|
2064
|
-
const property = definition.getProperty(propertyName);
|
|
2065
|
-
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
2066
|
-
return void 0;
|
|
2067
|
-
}
|
|
2068
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
2069
|
-
if (!initializer || !Node5.isArrayLiteralExpression(initializer)) {
|
|
2070
|
-
return void 0;
|
|
2071
|
-
}
|
|
2072
|
-
const values = initializer.getElements().map((element) => {
|
|
2073
|
-
const unwrapped = unwrapExpression(element);
|
|
2074
|
-
return unwrapped && Node5.isStringLiteral(unwrapped) ? unwrapped.getLiteralText() : void 0;
|
|
2075
|
-
});
|
|
2076
|
-
return values.every((value) => value !== void 0) ? values : void 0;
|
|
2077
|
-
}
|
|
2078
|
-
function readStringRecordProperty(definition, propertyName) {
|
|
2079
|
-
const object = readObjectProperty3(definition, propertyName);
|
|
2080
|
-
if (!object) {
|
|
2081
|
-
return void 0;
|
|
2082
|
-
}
|
|
2083
|
-
const record = {};
|
|
2084
|
-
for (const property of object.getProperties()) {
|
|
2085
|
-
if (!Node5.isPropertyAssignment(property)) {
|
|
2086
|
-
return void 0;
|
|
2087
|
-
}
|
|
2088
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
2089
|
-
if (!initializer || !Node5.isStringLiteral(initializer)) {
|
|
2090
|
-
return void 0;
|
|
2091
|
-
}
|
|
2092
|
-
record[property.getName().replace(/^["']|["']$/g, "")] = initializer.getLiteralText();
|
|
2093
|
-
}
|
|
2094
|
-
return record;
|
|
2095
|
-
}
|
|
2096
1787
|
function hasProperty(definition, propertyName) {
|
|
2097
1788
|
return Boolean(definition?.getProperty(propertyName));
|
|
2098
1789
|
}
|
|
2099
1790
|
|
|
2100
1791
|
// packages/compiler/src/diagnostics.ts
|
|
2101
|
-
import { existsSync as
|
|
1792
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2102
1793
|
import { readFile as readFile2 } from "fs/promises";
|
|
2103
|
-
import
|
|
1794
|
+
import path6 from "path";
|
|
2104
1795
|
async function collectProjectDiagnostics(rootDir, input) {
|
|
2105
1796
|
const diagnostics = [];
|
|
2106
1797
|
const tools = Array.isArray(input) ? input : input.tools;
|
|
2107
1798
|
const resources = Array.isArray(input) ? [] : input.resources ?? [];
|
|
2108
1799
|
const prompts = Array.isArray(input) ? [] : input.prompts ?? [];
|
|
2109
1800
|
const config = Array.isArray(input) ? void 0 : input.config;
|
|
2110
|
-
const hasAuthConfig =
|
|
1801
|
+
const hasAuthConfig = existsSync3(path6.join(rootDir, "auth.ts"));
|
|
2111
1802
|
for (const entry of tools) {
|
|
2112
|
-
const toolPath =
|
|
1803
|
+
const toolPath = path6.join(rootDir, entry.sourceFile);
|
|
2113
1804
|
const toolSource = await readFile2(toolPath, "utf8");
|
|
2114
|
-
diagnostics.push(...diagnoseToolSource(entry, toolSource, hasAuthConfig));
|
|
1805
|
+
diagnostics.push(...diagnoseToolSource(rootDir, entry, toolSource, hasAuthConfig));
|
|
2115
1806
|
if (entry.widget) {
|
|
2116
|
-
const widgetPath =
|
|
1807
|
+
const widgetPath = path6.join(rootDir, entry.widget.sourceFile);
|
|
2117
1808
|
const widgetSource = await readFile2(widgetPath, "utf8");
|
|
2118
1809
|
diagnostics.push(...diagnoseWidgetSource(rootDir, entry, widgetSource));
|
|
2119
1810
|
}
|
|
2120
1811
|
}
|
|
2121
1812
|
for (const entry of resources) {
|
|
2122
|
-
const resourcePath =
|
|
1813
|
+
const resourcePath = path6.join(rootDir, entry.sourceFile);
|
|
2123
1814
|
const resourceSource = await readFile2(resourcePath, "utf8");
|
|
2124
1815
|
diagnostics.push(...diagnoseResourceSource(entry, resourceSource));
|
|
2125
1816
|
}
|
|
2126
1817
|
for (const entry of prompts) {
|
|
2127
|
-
const promptPath =
|
|
1818
|
+
const promptPath = path6.join(rootDir, entry.sourceFile);
|
|
2128
1819
|
const promptSource = await readFile2(promptPath, "utf8");
|
|
2129
1820
|
diagnostics.push(...diagnosePromptSource(entry, promptSource));
|
|
2130
1821
|
}
|
|
@@ -2139,7 +1830,7 @@ function formatDiagnostic(diagnostic) {
|
|
|
2139
1830
|
hint: ${diagnostic.hint}` : "";
|
|
2140
1831
|
return `${location} - ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}${hint}`;
|
|
2141
1832
|
}
|
|
2142
|
-
function diagnoseToolSource(entry, source, hasAuthConfig) {
|
|
1833
|
+
function diagnoseToolSource(rootDir, entry, source, hasAuthConfig) {
|
|
2143
1834
|
const diagnostics = [];
|
|
2144
1835
|
const toolLocation = locate(source, "tool({");
|
|
2145
1836
|
if (!entry.description.trim().startsWith("Use this when")) {
|
|
@@ -2356,21 +2047,21 @@ function isIgnored(source, code) {
|
|
|
2356
2047
|
|
|
2357
2048
|
// packages/compiler/src/generated.ts
|
|
2358
2049
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
2359
|
-
import
|
|
2050
|
+
import path7 from "path";
|
|
2360
2051
|
async function writeGeneratedTypes(rootDir, tools) {
|
|
2361
|
-
const generatedDir =
|
|
2052
|
+
const generatedDir = path7.join(rootDir, ".sidecar", "generated");
|
|
2362
2053
|
await mkdir2(generatedDir, { recursive: true });
|
|
2363
2054
|
const appCallableTools = tools.filter(isAppCallable);
|
|
2364
2055
|
const methodNames = uniqueMethodNames(appCallableTools.map((entry) => toIdentifier(entry.id)));
|
|
2365
2056
|
const imports = appCallableTools.map(
|
|
2366
|
-
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir,
|
|
2057
|
+
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir, path7.join(rootDir, entry.sourceFile), { extension: "js" }))};`
|
|
2367
2058
|
).join("\n");
|
|
2368
2059
|
const ids = appCallableTools.map((entry, index) => ` ${methodNames[index]}: ${JSON.stringify(entry.id)}`).join(",\n");
|
|
2369
2060
|
const toolTypes = appCallableTools.map(
|
|
2370
|
-
(
|
|
2061
|
+
(entry, index) => ` ${methodNames[index]}(params: ToolParams<typeof tool${index}>): Promise<ToolOutput<typeof tool${index}>>;`
|
|
2371
2062
|
).join("\n");
|
|
2372
2063
|
await writeFile2(
|
|
2373
|
-
|
|
2064
|
+
path7.join(generatedDir, "tools.ts"),
|
|
2374
2065
|
`/**
|
|
2375
2066
|
* Generated Sidecar widget tool client.
|
|
2376
2067
|
*
|
|
@@ -2420,13 +2111,13 @@ function uniqueMethodNames(names) {
|
|
|
2420
2111
|
|
|
2421
2112
|
// packages/compiler/src/identity.ts
|
|
2422
2113
|
import { readFile as readFile3 } from "fs/promises";
|
|
2423
|
-
import
|
|
2114
|
+
import path8 from "path";
|
|
2424
2115
|
async function loadProjectIdentity(rootDir) {
|
|
2425
|
-
const packageJson = await readOptionalJson(
|
|
2116
|
+
const packageJson = await readOptionalJson(path8.join(rootDir, "package.json"));
|
|
2426
2117
|
const configText = await readOptionalText(
|
|
2427
|
-
|
|
2118
|
+
path8.join(rootDir, "sidecar.config.ts")
|
|
2428
2119
|
);
|
|
2429
|
-
const name = readConfigString(configText, "name") ?? packageJson?.name ??
|
|
2120
|
+
const name = readConfigString(configText, "name") ?? packageJson?.name ?? path8.basename(rootDir);
|
|
2430
2121
|
const version = readConfigString(configText, "version") ?? packageJson?.version ?? "0.0.0-dev";
|
|
2431
2122
|
const description = readConfigString(configText, "description") ?? packageJson?.description ?? `${name} Sidecar app.`;
|
|
2432
2123
|
return {
|
|
@@ -2460,32 +2151,32 @@ function readConfigString(configText, key) {
|
|
|
2460
2151
|
|
|
2461
2152
|
// packages/compiler/src/plugins.ts
|
|
2462
2153
|
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
2463
|
-
import
|
|
2154
|
+
import path14 from "path";
|
|
2464
2155
|
|
|
2465
2156
|
// packages/compiler/src/plugin-components/agents.ts
|
|
2466
2157
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
2467
|
-
import
|
|
2158
|
+
import path9 from "path";
|
|
2468
2159
|
async function emitClaudeAgents(rootDir, destination) {
|
|
2469
|
-
const source =
|
|
2160
|
+
const source = path9.join(rootDir, "agents");
|
|
2470
2161
|
if (!existsSyncSafe(source)) {
|
|
2471
2162
|
return;
|
|
2472
2163
|
}
|
|
2473
2164
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
2474
2165
|
const agentDirs = entries.filter(
|
|
2475
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
2166
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path9.join(source, entry.name, "agent.ts"))
|
|
2476
2167
|
);
|
|
2477
2168
|
if (!agentDirs.length) {
|
|
2478
2169
|
return;
|
|
2479
2170
|
}
|
|
2480
2171
|
await mkdir3(destination, { recursive: true });
|
|
2481
2172
|
for (const entry of agentDirs) {
|
|
2482
|
-
const sourceText = await readFile4(
|
|
2173
|
+
const sourceText = await readFile4(path9.join(source, entry.name, "agent.ts"), "utf8");
|
|
2483
2174
|
const markdown = parseClaudeAgent(
|
|
2484
2175
|
sourceText,
|
|
2485
2176
|
entry.name
|
|
2486
2177
|
);
|
|
2487
2178
|
const agentName = readObjectString(sourceText, "name") ?? entry.name;
|
|
2488
|
-
await writeFile3(
|
|
2179
|
+
await writeFile3(path9.join(destination, `${safeFileStem(agentName)}.md`), markdown);
|
|
2489
2180
|
}
|
|
2490
2181
|
}
|
|
2491
2182
|
function parseClaudeAgent(source, fallbackName) {
|
|
@@ -2514,41 +2205,41 @@ ${prompt.trim()}
|
|
|
2514
2205
|
|
|
2515
2206
|
// packages/compiler/src/plugin-components/commands.ts
|
|
2516
2207
|
import { cp, lstat, mkdir as mkdir4, readdir as readdir3, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
2517
|
-
import
|
|
2208
|
+
import path10 from "path";
|
|
2518
2209
|
async function copyCommands(rootDir, destination) {
|
|
2519
|
-
const source =
|
|
2210
|
+
const source = path10.join(rootDir, "commands");
|
|
2520
2211
|
if (!existsSyncSafe(source)) {
|
|
2521
2212
|
return;
|
|
2522
2213
|
}
|
|
2523
2214
|
await mkdir4(destination, { recursive: true });
|
|
2524
2215
|
const entries = await readdir3(source, { withFileTypes: true });
|
|
2525
2216
|
for (const entry of entries) {
|
|
2526
|
-
const sourcePath =
|
|
2217
|
+
const sourcePath = path10.join(source, entry.name);
|
|
2527
2218
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2528
2219
|
if (await safeCommandCopyFilter(sourcePath)) {
|
|
2529
|
-
await cp(sourcePath,
|
|
2220
|
+
await cp(sourcePath, path10.join(destination, safeFileStem(entry.name.replace(/\.md$/, "")) + ".md"));
|
|
2530
2221
|
}
|
|
2531
2222
|
continue;
|
|
2532
2223
|
}
|
|
2533
2224
|
if (!entry.isDirectory()) {
|
|
2534
2225
|
continue;
|
|
2535
2226
|
}
|
|
2536
|
-
const dynamicCommand =
|
|
2227
|
+
const dynamicCommand = path10.join(sourcePath, "command.ts");
|
|
2537
2228
|
if (existsSyncSafe(dynamicCommand)) {
|
|
2538
2229
|
const sourceText = await readFile5(dynamicCommand, "utf8");
|
|
2539
2230
|
const markdown = parseDynamicCommand(sourceText, entry.name);
|
|
2540
2231
|
const commandName = readObjectString(sourceText, "name") ?? entry.name;
|
|
2541
|
-
await writeFile4(
|
|
2232
|
+
await writeFile4(path10.join(destination, `${safeFileStem(commandName)}.md`), markdown);
|
|
2542
2233
|
continue;
|
|
2543
2234
|
}
|
|
2544
|
-
await cp(sourcePath,
|
|
2235
|
+
await cp(sourcePath, path10.join(destination, entry.name), {
|
|
2545
2236
|
recursive: true,
|
|
2546
2237
|
filter: safeCommandCopyFilter
|
|
2547
2238
|
});
|
|
2548
2239
|
}
|
|
2549
2240
|
}
|
|
2550
2241
|
async function safeCommandCopyFilter(sourcePath) {
|
|
2551
|
-
const basename =
|
|
2242
|
+
const basename = path10.basename(sourcePath);
|
|
2552
2243
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2553
2244
|
return false;
|
|
2554
2245
|
}
|
|
@@ -2577,32 +2268,32 @@ ${Object.entries(frontmatter).map(([key, value]) => `${key}: ${yamlScalar(value)
|
|
|
2577
2268
|
|
|
2578
2269
|
// packages/compiler/src/plugin-components/hooks.ts
|
|
2579
2270
|
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
2580
|
-
import
|
|
2271
|
+
import path11 from "path";
|
|
2581
2272
|
import {
|
|
2582
2273
|
Node as Node6,
|
|
2583
2274
|
Project as Project2,
|
|
2584
2275
|
SyntaxKind as SyntaxKind4
|
|
2585
2276
|
} from "ts-morph";
|
|
2586
2277
|
async function copyHooks(rootDir, destination) {
|
|
2587
|
-
const source =
|
|
2278
|
+
const source = path11.join(rootDir, "hooks");
|
|
2588
2279
|
if (!existsSyncSafe(source)) {
|
|
2589
2280
|
return;
|
|
2590
2281
|
}
|
|
2591
2282
|
const entries = await readdir4(source, { withFileTypes: true });
|
|
2592
2283
|
const hookDirs = entries.filter(
|
|
2593
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
2284
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path11.join(source, entry.name, "hook.ts"))
|
|
2594
2285
|
);
|
|
2595
2286
|
if (!hookDirs.length) {
|
|
2596
2287
|
return;
|
|
2597
2288
|
}
|
|
2598
2289
|
const config = {};
|
|
2599
2290
|
for (const entry of hookDirs) {
|
|
2600
|
-
const filePath =
|
|
2291
|
+
const filePath = path11.join(source, entry.name, "hook.ts");
|
|
2601
2292
|
mergeHooks(config, parseHookFile(await readFile6(filePath, "utf8"), entry.name));
|
|
2602
2293
|
}
|
|
2603
2294
|
await mkdir5(destination, { recursive: true });
|
|
2604
2295
|
await writeFile5(
|
|
2605
|
-
|
|
2296
|
+
path11.join(destination, "hooks.json"),
|
|
2606
2297
|
`${JSON.stringify(config, null, 2)}
|
|
2607
2298
|
`
|
|
2608
2299
|
);
|
|
@@ -2629,7 +2320,7 @@ function parseHookFile(source, fallbackName) {
|
|
|
2629
2320
|
throw new Error(`hooks/${fallbackName}/hook.ts must default-export hook({ ... }) or hooks({ ... }).`);
|
|
2630
2321
|
}
|
|
2631
2322
|
function parseHookDefinition(definition, fallbackName) {
|
|
2632
|
-
const event =
|
|
2323
|
+
const event = readStringProperty3(definition, "event");
|
|
2633
2324
|
if (!event) {
|
|
2634
2325
|
throw new Error(`hooks/${fallbackName}/hook.ts must declare an event string.`);
|
|
2635
2326
|
}
|
|
@@ -2639,7 +2330,7 @@ function parseHookDefinition(definition, fallbackName) {
|
|
|
2639
2330
|
}
|
|
2640
2331
|
return {
|
|
2641
2332
|
event,
|
|
2642
|
-
matcher:
|
|
2333
|
+
matcher: readStringProperty3(definition, "matcher"),
|
|
2643
2334
|
run: hooks
|
|
2644
2335
|
};
|
|
2645
2336
|
}
|
|
@@ -2659,7 +2350,7 @@ function parseHooksDefinition(definition, fallbackName) {
|
|
|
2659
2350
|
throw new Error(`hooks/${fallbackName}/hook.ts event "${event}" entries must be objects.`);
|
|
2660
2351
|
}
|
|
2661
2352
|
return stripUndefined2({
|
|
2662
|
-
matcher:
|
|
2353
|
+
matcher: readStringProperty3(entry, "matcher"),
|
|
2663
2354
|
hooks: readHookArray(entry, "run", fallbackName)
|
|
2664
2355
|
});
|
|
2665
2356
|
});
|
|
@@ -2682,7 +2373,7 @@ function parseHookHandlers(handlers, fallbackName) {
|
|
|
2682
2373
|
}
|
|
2683
2374
|
function parseHookHandler(handler, fallbackName) {
|
|
2684
2375
|
if (Node6.isObjectLiteralExpression(handler)) {
|
|
2685
|
-
const type =
|
|
2376
|
+
const type = readStringProperty3(handler, "type");
|
|
2686
2377
|
if (type !== "command" && type !== "http") {
|
|
2687
2378
|
throw new Error(`hooks/${fallbackName}/hook.ts hook handlers need type "command" or "http".`);
|
|
2688
2379
|
}
|
|
@@ -2732,7 +2423,7 @@ function objectLiteralToRecord(object) {
|
|
|
2732
2423
|
}
|
|
2733
2424
|
return stripUndefined2(record);
|
|
2734
2425
|
}
|
|
2735
|
-
function
|
|
2426
|
+
function readStringProperty3(object, propertyName) {
|
|
2736
2427
|
const property = object.getProperty(propertyName);
|
|
2737
2428
|
if (!property || !Node6.isPropertyAssignment(property)) {
|
|
2738
2429
|
return void 0;
|
|
@@ -2776,7 +2467,7 @@ function mergeHooks(target, source) {
|
|
|
2776
2467
|
|
|
2777
2468
|
// packages/compiler/src/plugin-components/passthrough.ts
|
|
2778
2469
|
import { cp as cp2, lstat as lstat2 } from "fs/promises";
|
|
2779
|
-
import
|
|
2470
|
+
import path12 from "path";
|
|
2780
2471
|
async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
2781
2472
|
for (const directory of [
|
|
2782
2473
|
"assets",
|
|
@@ -2785,18 +2476,18 @@ async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
|
2785
2476
|
"output-styles",
|
|
2786
2477
|
"themes"
|
|
2787
2478
|
]) {
|
|
2788
|
-
const source =
|
|
2479
|
+
const source = path12.join(rootDir, directory);
|
|
2789
2480
|
if (!existsSyncSafe(source)) {
|
|
2790
2481
|
continue;
|
|
2791
2482
|
}
|
|
2792
|
-
await cp2(source,
|
|
2483
|
+
await cp2(source, path12.join(pluginDir, directory), {
|
|
2793
2484
|
recursive: true,
|
|
2794
2485
|
filter: safePluginCopyFilter
|
|
2795
2486
|
});
|
|
2796
2487
|
}
|
|
2797
2488
|
}
|
|
2798
2489
|
async function safePluginCopyFilter(sourcePath) {
|
|
2799
|
-
const basename =
|
|
2490
|
+
const basename = path12.basename(sourcePath);
|
|
2800
2491
|
if (basename === "node_modules" || basename === ".git" || basename === ".env" || basename.startsWith(".env.")) {
|
|
2801
2492
|
return false;
|
|
2802
2493
|
}
|
|
@@ -2805,11 +2496,11 @@ async function safePluginCopyFilter(sourcePath) {
|
|
|
2805
2496
|
}
|
|
2806
2497
|
|
|
2807
2498
|
// packages/compiler/src/plugin-components/skills.ts
|
|
2808
|
-
import { existsSync as
|
|
2499
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2809
2500
|
import { cp as cp3, lstat as lstat3, mkdir as mkdir6, readdir as readdir5, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
2810
|
-
import
|
|
2501
|
+
import path13 from "path";
|
|
2811
2502
|
async function copySkills(rootDir, destination) {
|
|
2812
|
-
const source =
|
|
2503
|
+
const source = path13.join(rootDir, "skills");
|
|
2813
2504
|
if (!existsSyncSafe(source)) {
|
|
2814
2505
|
return;
|
|
2815
2506
|
}
|
|
@@ -2819,27 +2510,27 @@ async function copySkills(rootDir, destination) {
|
|
|
2819
2510
|
if (!entry.isDirectory()) {
|
|
2820
2511
|
continue;
|
|
2821
2512
|
}
|
|
2822
|
-
const sourceDir =
|
|
2823
|
-
const destinationDir =
|
|
2824
|
-
const staticSkill =
|
|
2825
|
-
const dynamicSkill =
|
|
2513
|
+
const sourceDir = path13.join(source, entry.name);
|
|
2514
|
+
const destinationDir = path13.join(destination, entry.name);
|
|
2515
|
+
const staticSkill = path13.join(sourceDir, "SKILL.md");
|
|
2516
|
+
const dynamicSkill = path13.join(sourceDir, "skill.ts");
|
|
2826
2517
|
await mkdir6(destinationDir, { recursive: true });
|
|
2827
|
-
if (
|
|
2518
|
+
if (existsSync4(staticSkill)) {
|
|
2828
2519
|
await cp3(sourceDir, destinationDir, {
|
|
2829
2520
|
recursive: true,
|
|
2830
|
-
filter: async (sourcePath) => !sourcePath.endsWith(`${
|
|
2521
|
+
filter: async (sourcePath) => !sourcePath.endsWith(`${path13.sep}skill.ts`) && await safeSkillCopyFilter(sourcePath)
|
|
2831
2522
|
});
|
|
2832
|
-
} else if (
|
|
2523
|
+
} else if (existsSync4(dynamicSkill)) {
|
|
2833
2524
|
const generated = parseDynamicSkill(
|
|
2834
2525
|
await readFile7(dynamicSkill, "utf8"),
|
|
2835
2526
|
entry.name
|
|
2836
2527
|
);
|
|
2837
|
-
await writeFile6(
|
|
2528
|
+
await writeFile6(path13.join(destinationDir, "SKILL.md"), generated);
|
|
2838
2529
|
}
|
|
2839
2530
|
}
|
|
2840
2531
|
}
|
|
2841
2532
|
async function safeSkillCopyFilter(sourcePath) {
|
|
2842
|
-
const basename =
|
|
2533
|
+
const basename = path13.basename(sourcePath);
|
|
2843
2534
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2844
2535
|
return false;
|
|
2845
2536
|
}
|
|
@@ -2865,25 +2556,25 @@ async function buildPluginPackages(rootDir, outRoot, manifest) {
|
|
|
2865
2556
|
await buildClaudePlugin(rootDir, outRoot, identity, manifest);
|
|
2866
2557
|
}
|
|
2867
2558
|
async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
2868
|
-
const pluginDir =
|
|
2869
|
-
await mkdir7(
|
|
2870
|
-
await copySkills(rootDir,
|
|
2871
|
-
await copyCommands(rootDir,
|
|
2872
|
-
await copyHooks(rootDir,
|
|
2873
|
-
await emitClaudeAgents(rootDir,
|
|
2559
|
+
const pluginDir = path14.join(outRoot, "claude-plugin");
|
|
2560
|
+
await mkdir7(path14.join(pluginDir, ".claude-plugin"), { recursive: true });
|
|
2561
|
+
await copySkills(rootDir, path14.join(pluginDir, "skills"));
|
|
2562
|
+
await copyCommands(rootDir, path14.join(pluginDir, "commands"));
|
|
2563
|
+
await copyHooks(rootDir, path14.join(pluginDir, "hooks"));
|
|
2564
|
+
await emitClaudeAgents(rootDir, path14.join(pluginDir, "agents"));
|
|
2874
2565
|
await copyClaudePassthroughDirectories(rootDir, pluginDir);
|
|
2875
|
-
await writeJson(
|
|
2566
|
+
await writeJson(path14.join(pluginDir, ".claude-plugin", "plugin.json"), {
|
|
2876
2567
|
name: identity.slug,
|
|
2877
2568
|
version: identity.version,
|
|
2878
2569
|
description: identity.description,
|
|
2879
2570
|
displayName: identity.name,
|
|
2880
2571
|
installationPreference: "available"
|
|
2881
2572
|
});
|
|
2882
|
-
await writeJson(
|
|
2573
|
+
await writeJson(path14.join(pluginDir, "version.json"), {
|
|
2883
2574
|
version: identity.version,
|
|
2884
2575
|
generatedBy: "sidecar"
|
|
2885
2576
|
});
|
|
2886
|
-
await writeJson(
|
|
2577
|
+
await writeJson(path14.join(pluginDir, ".mcp.json"), {
|
|
2887
2578
|
mcpServers: {
|
|
2888
2579
|
[identity.slug]: {
|
|
2889
2580
|
type: "http",
|
|
@@ -2891,7 +2582,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2891
2582
|
}
|
|
2892
2583
|
}
|
|
2893
2584
|
});
|
|
2894
|
-
await writeJson(
|
|
2585
|
+
await writeJson(path14.join(pluginDir, "settings.json"), {
|
|
2895
2586
|
sidecar: {
|
|
2896
2587
|
tools: manifest.tools.map((entry) => entry.id),
|
|
2897
2588
|
resources: manifest.resources.map((entry) => entry.uri),
|
|
@@ -2899,7 +2590,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2899
2590
|
}
|
|
2900
2591
|
});
|
|
2901
2592
|
await writeFile7(
|
|
2902
|
-
|
|
2593
|
+
path14.join(pluginDir, "README.md"),
|
|
2903
2594
|
`# ${identity.name} Claude Plugin
|
|
2904
2595
|
|
|
2905
2596
|
This package was generated by Sidecar.
|
|
@@ -2913,7 +2604,7 @@ Claude/Cowork plugin-specific components such as skills, slash commands, agents,
|
|
|
2913
2604
|
);
|
|
2914
2605
|
}
|
|
2915
2606
|
async function writeJson(filePath, value) {
|
|
2916
|
-
await mkdir7(
|
|
2607
|
+
await mkdir7(path14.dirname(filePath), { recursive: true });
|
|
2917
2608
|
await writeFile7(
|
|
2918
2609
|
filePath,
|
|
2919
2610
|
`${JSON.stringify(stripUndefined2(value), null, 2)}
|
|
@@ -2923,13 +2614,13 @@ async function writeJson(filePath, value) {
|
|
|
2923
2614
|
|
|
2924
2615
|
// packages/compiler/src/prompts.ts
|
|
2925
2616
|
import { readdir as readdir6 } from "fs/promises";
|
|
2926
|
-
import
|
|
2617
|
+
import path15 from "path";
|
|
2927
2618
|
import {
|
|
2928
2619
|
Node as Node7,
|
|
2929
2620
|
SyntaxKind as SyntaxKind5
|
|
2930
2621
|
} from "ts-morph";
|
|
2931
2622
|
async function analyzeProjectPrompts(rootDir) {
|
|
2932
|
-
const promptFiles = await findPromptFiles(
|
|
2623
|
+
const promptFiles = await findPromptFiles(path15.join(rootDir, "prompts"));
|
|
2933
2624
|
if (promptFiles.length === 0) {
|
|
2934
2625
|
return [];
|
|
2935
2626
|
}
|
|
@@ -2941,7 +2632,7 @@ async function analyzeProjectPrompts(rootDir) {
|
|
|
2941
2632
|
function analyzePromptFile(sourceFile, rootDir) {
|
|
2942
2633
|
const definition = findPromptDefinition(sourceFile);
|
|
2943
2634
|
const absoluteFile = sourceFile.getFilePath();
|
|
2944
|
-
const directory =
|
|
2635
|
+
const directory = path15.basename(path15.dirname(absoluteFile));
|
|
2945
2636
|
const name = getOptionalStringProperty2(definition, "name") ?? safePathSegment(directory);
|
|
2946
2637
|
const title = getRequiredStringProperty2(definition, "title", sourceFile);
|
|
2947
2638
|
const description = getOptionalStringProperty2(definition, "description");
|
|
@@ -2957,7 +2648,7 @@ function analyzePromptFile(sourceFile, rootDir) {
|
|
|
2957
2648
|
throw new CompilerError(sourceFile, "prompt({ ... }) must include a run method.");
|
|
2958
2649
|
}
|
|
2959
2650
|
return {
|
|
2960
|
-
sourceFile:
|
|
2651
|
+
sourceFile: path15.relative(rootDir, absoluteFile),
|
|
2961
2652
|
directory,
|
|
2962
2653
|
name,
|
|
2963
2654
|
title,
|
|
@@ -2976,7 +2667,7 @@ async function findPromptFiles(promptsDir) {
|
|
|
2976
2667
|
if (!entry.isDirectory()) {
|
|
2977
2668
|
continue;
|
|
2978
2669
|
}
|
|
2979
|
-
const filePath =
|
|
2670
|
+
const filePath = path15.join(promptsDir, entry.name, "prompt.ts");
|
|
2980
2671
|
if (existsSyncSafe(filePath)) {
|
|
2981
2672
|
files.push(filePath);
|
|
2982
2673
|
}
|
|
@@ -3098,7 +2789,7 @@ function readIcons(definition) {
|
|
|
3098
2789
|
return [{
|
|
3099
2790
|
src,
|
|
3100
2791
|
mimeType: getOptionalStringProperty2(object, "mimeType"),
|
|
3101
|
-
sizes:
|
|
2792
|
+
sizes: readStringArrayProperty3(object, "sizes")
|
|
3102
2793
|
}];
|
|
3103
2794
|
});
|
|
3104
2795
|
return icons.length ? icons : void 0;
|
|
@@ -3111,7 +2802,7 @@ function readObjectProperty4(definition, propertyName) {
|
|
|
3111
2802
|
const initializer = unwrapExpression(property.getInitializer());
|
|
3112
2803
|
return initializer && Node7.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
3113
2804
|
}
|
|
3114
|
-
function
|
|
2805
|
+
function readStringArrayProperty3(definition, propertyName) {
|
|
3115
2806
|
const property = definition.getProperty(propertyName);
|
|
3116
2807
|
if (!property || !Node7.isPropertyAssignment(property)) {
|
|
3117
2808
|
return void 0;
|
|
@@ -3125,13 +2816,13 @@ function readStringArrayProperty4(definition, propertyName) {
|
|
|
3125
2816
|
|
|
3126
2817
|
// packages/compiler/src/resources.ts
|
|
3127
2818
|
import { readdir as readdir7 } from "fs/promises";
|
|
3128
|
-
import
|
|
2819
|
+
import path16 from "path";
|
|
3129
2820
|
import {
|
|
3130
2821
|
Node as Node8,
|
|
3131
2822
|
SyntaxKind as SyntaxKind6
|
|
3132
2823
|
} from "ts-morph";
|
|
3133
2824
|
async function analyzeProjectResources(rootDir) {
|
|
3134
|
-
const resourceFiles = await findResourceFiles(
|
|
2825
|
+
const resourceFiles = await findResourceFiles(path16.join(rootDir, "resources"));
|
|
3135
2826
|
if (resourceFiles.length === 0) {
|
|
3136
2827
|
return [];
|
|
3137
2828
|
}
|
|
@@ -3143,7 +2834,7 @@ async function analyzeProjectResources(rootDir) {
|
|
|
3143
2834
|
function analyzeResourceFile(sourceFile, rootDir) {
|
|
3144
2835
|
const definition = findResourceDefinition(sourceFile);
|
|
3145
2836
|
const absoluteFile = sourceFile.getFilePath();
|
|
3146
|
-
const directory =
|
|
2837
|
+
const directory = path16.basename(path16.dirname(absoluteFile));
|
|
3147
2838
|
const defaultUri = `sidecar://resources/${safePathSegment(directory)}`;
|
|
3148
2839
|
const name = getRequiredStringProperty3(definition, "name", sourceFile);
|
|
3149
2840
|
const uri = getOptionalStringProperty3(definition, "uri") ?? defaultUri;
|
|
@@ -3161,7 +2852,7 @@ function analyzeResourceFile(sourceFile, rootDir) {
|
|
|
3161
2852
|
throw new CompilerError(sourceFile, "resource({ ... }) must include a read method.");
|
|
3162
2853
|
}
|
|
3163
2854
|
return {
|
|
3164
|
-
sourceFile:
|
|
2855
|
+
sourceFile: path16.relative(rootDir, absoluteFile),
|
|
3165
2856
|
directory,
|
|
3166
2857
|
uri,
|
|
3167
2858
|
name,
|
|
@@ -3184,7 +2875,7 @@ async function findResourceFiles(resourcesDir) {
|
|
|
3184
2875
|
if (!entry.isDirectory()) {
|
|
3185
2876
|
continue;
|
|
3186
2877
|
}
|
|
3187
|
-
const filePath =
|
|
2878
|
+
const filePath = path16.join(resourcesDir, entry.name, "resource.ts");
|
|
3188
2879
|
if (existsSyncSafe(filePath)) {
|
|
3189
2880
|
files.push(filePath);
|
|
3190
2881
|
}
|
|
@@ -3263,7 +2954,7 @@ function readAnnotations2(definition) {
|
|
|
3263
2954
|
return void 0;
|
|
3264
2955
|
}
|
|
3265
2956
|
const annotations = {};
|
|
3266
|
-
const audience =
|
|
2957
|
+
const audience = readStringArrayProperty4(initializer, "audience")?.filter((value) => value === "user" || value === "assistant");
|
|
3267
2958
|
const priority = getOptionalNumberProperty(initializer, "priority");
|
|
3268
2959
|
const lastModified = getOptionalStringProperty3(initializer, "lastModified");
|
|
3269
2960
|
if (audience?.length) annotations.audience = audience;
|
|
@@ -3292,7 +2983,7 @@ function readIcons2(definition) {
|
|
|
3292
2983
|
return [{
|
|
3293
2984
|
src,
|
|
3294
2985
|
mimeType: getOptionalStringProperty3(object, "mimeType"),
|
|
3295
|
-
sizes:
|
|
2986
|
+
sizes: readStringArrayProperty4(object, "sizes")
|
|
3296
2987
|
}];
|
|
3297
2988
|
});
|
|
3298
2989
|
return icons.length ? icons : void 0;
|
|
@@ -3305,7 +2996,7 @@ function readObjectProperty5(definition, propertyName) {
|
|
|
3305
2996
|
const initializer = unwrapExpression(property.getInitializer());
|
|
3306
2997
|
return initializer && Node8.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
3307
2998
|
}
|
|
3308
|
-
function
|
|
2999
|
+
function readStringArrayProperty4(definition, propertyName) {
|
|
3309
3000
|
const property = definition.getProperty(propertyName);
|
|
3310
3001
|
if (!property || !Node8.isPropertyAssignment(property)) {
|
|
3311
3002
|
return void 0;
|
|
@@ -3318,21 +3009,21 @@ function readStringArrayProperty5(definition, propertyName) {
|
|
|
3318
3009
|
}
|
|
3319
3010
|
|
|
3320
3011
|
// packages/compiler/src/server-output.ts
|
|
3321
|
-
import { existsSync as
|
|
3012
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3322
3013
|
import { mkdir as mkdir8, rm, writeFile as writeFile8 } from "fs/promises";
|
|
3323
|
-
import
|
|
3014
|
+
import path17 from "path";
|
|
3324
3015
|
import { build as esbuild2 } from "esbuild";
|
|
3325
3016
|
var SERVER_ENTRYPOINT = "server/index.js";
|
|
3326
3017
|
var VERCEL_FUNCTION_DIR = "functions/api/sidecar.func";
|
|
3327
3018
|
var VERCEL_ENTRYPOINT = `${VERCEL_FUNCTION_DIR}/index.js`;
|
|
3328
3019
|
var VERCEL_HANDLER_FILE = "index.js";
|
|
3329
3020
|
async function buildServerOutput(rootDir, outDir, manifest, identity, host = "node", options = {}) {
|
|
3330
|
-
const cacheDir =
|
|
3021
|
+
const cacheDir = path17.join(rootDir, ".sidecar", "cache", "server");
|
|
3331
3022
|
await mkdir8(cacheDir, { recursive: true });
|
|
3332
|
-
const entryFile =
|
|
3023
|
+
const entryFile = path17.join(cacheDir, "index.ts");
|
|
3333
3024
|
await writeFile8(entryFile, renderServerEntry(rootDir, entryFile, manifest, identity));
|
|
3334
|
-
const serverFile =
|
|
3335
|
-
await mkdir8(
|
|
3025
|
+
const serverFile = path17.join(outDir, SERVER_ENTRYPOINT);
|
|
3026
|
+
await mkdir8(path17.dirname(serverFile), { recursive: true });
|
|
3336
3027
|
await esbuild2({
|
|
3337
3028
|
absWorkingDir: rootDir,
|
|
3338
3029
|
alias: sidecarBundleAliases(rootDir),
|
|
@@ -3346,30 +3037,30 @@ const require = __sidecarCreateRequire(import.meta.url);`
|
|
|
3346
3037
|
legalComments: "none",
|
|
3347
3038
|
minify: false,
|
|
3348
3039
|
nodePaths: [
|
|
3349
|
-
|
|
3350
|
-
|
|
3040
|
+
path17.join(rootDir, "node_modules"),
|
|
3041
|
+
path17.join(process.cwd(), "node_modules")
|
|
3351
3042
|
],
|
|
3352
3043
|
outfile: serverFile,
|
|
3353
3044
|
platform: "node",
|
|
3354
3045
|
sourcemap: false,
|
|
3355
3046
|
target: "node20"
|
|
3356
3047
|
});
|
|
3357
|
-
await writeFile8(
|
|
3048
|
+
await writeFile8(path17.join(outDir, "package.json"), renderServerPackage(identity));
|
|
3358
3049
|
if (host === "vercel") {
|
|
3359
3050
|
const vercelOutputDir = options.vercelOutputDir ?? outDir;
|
|
3360
|
-
await rm(
|
|
3361
|
-
await rm(
|
|
3362
|
-
await writeFile8(
|
|
3363
|
-
await writeFile8(
|
|
3051
|
+
await rm(path17.join(vercelOutputDir, "api"), { recursive: true, force: true });
|
|
3052
|
+
await rm(path17.join(vercelOutputDir, "vercel.json"), { force: true });
|
|
3053
|
+
await writeFile8(path17.join(outDir, VERCEL_HANDLER_FILE), renderVercelEntrypoint());
|
|
3054
|
+
await writeFile8(path17.join(outDir, ".vc-config.json"), renderVercelFunctionConfig());
|
|
3364
3055
|
await mkdir8(vercelOutputDir, { recursive: true });
|
|
3365
|
-
await writeFile8(
|
|
3056
|
+
await writeFile8(path17.join(vercelOutputDir, "config.json"), renderVercelOutputConfig());
|
|
3366
3057
|
} else {
|
|
3367
|
-
await rm(
|
|
3368
|
-
await rm(
|
|
3058
|
+
await rm(path17.join(outDir, "api"), { recursive: true, force: true });
|
|
3059
|
+
await rm(path17.join(outDir, "vercel.json"), { force: true });
|
|
3369
3060
|
}
|
|
3370
3061
|
}
|
|
3371
3062
|
function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
3372
|
-
const entryDir =
|
|
3063
|
+
const entryDir = path17.dirname(entryFile);
|
|
3373
3064
|
const tools = manifest.tools;
|
|
3374
3065
|
const resources = manifest.resources;
|
|
3375
3066
|
const prompts = manifest.prompts;
|
|
@@ -3382,17 +3073,17 @@ function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
|
3382
3073
|
`import { isSidecarPrompt, isSidecarResource, isSidecarTool } from "@sidecar-ai/core";`,
|
|
3383
3074
|
`import { isSidecarProxy } from "@sidecar-ai/server/proxy";`,
|
|
3384
3075
|
...tools.map(
|
|
3385
|
-
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3076
|
+
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3386
3077
|
),
|
|
3387
3078
|
...resources.map(
|
|
3388
|
-
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3079
|
+
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3389
3080
|
),
|
|
3390
3081
|
...prompts.map(
|
|
3391
|
-
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3082
|
+
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3392
3083
|
),
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3084
|
+
existsSync5(path17.join(rootDir, "auth.ts")) ? `import authExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "auth.ts")))};` : `const authExport = undefined;`,
|
|
3085
|
+
existsSync5(path17.join(rootDir, "proxy.ts")) ? `import proxyExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "proxy.ts")))};` : `const proxyExport = undefined;`,
|
|
3086
|
+
existsSync5(path17.join(rootDir, "sidecar.config.ts")) ? `import configExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "sidecar.config.ts")))};` : `const configExport = undefined;`
|
|
3396
3087
|
].join("\n");
|
|
3397
3088
|
return `${imports}
|
|
3398
3089
|
|
|
@@ -3503,7 +3194,7 @@ function unwrapRuntimeDefault(value) {
|
|
|
3503
3194
|
value &&
|
|
3504
3195
|
typeof value === "object" &&
|
|
3505
3196
|
"default" in value &&
|
|
3506
|
-
Object.keys(value).
|
|
3197
|
+
Object.keys(value).length === 1
|
|
3507
3198
|
) {
|
|
3508
3199
|
return unwrapRuntimeDefault(value.default);
|
|
3509
3200
|
}
|
|
@@ -3595,35 +3286,35 @@ function sidecarBundleAliases(rootDir) {
|
|
|
3595
3286
|
return void 0;
|
|
3596
3287
|
}
|
|
3597
3288
|
return {
|
|
3598
|
-
"sidecar-ai":
|
|
3599
|
-
"@sidecar-ai/auth":
|
|
3600
|
-
"@sidecar-ai/core":
|
|
3601
|
-
"@sidecar-ai/server":
|
|
3602
|
-
"@sidecar-ai/server/proxy":
|
|
3603
|
-
"@sidecar-ai/client":
|
|
3604
|
-
"@sidecar-ai/react":
|
|
3605
|
-
"@sidecar-ai/native":
|
|
3606
|
-
"@sidecar-ai/native/components":
|
|
3607
|
-
"@sidecar-ai/openai":
|
|
3608
|
-
"@sidecar-ai/openai/components":
|
|
3609
|
-
"@sidecar-ai/openai/official":
|
|
3610
|
-
"@sidecar-ai/anthropic":
|
|
3611
|
-
"@sidecar-ai/anthropic/agent":
|
|
3612
|
-
"@sidecar-ai/anthropic/command":
|
|
3613
|
-
"@sidecar-ai/anthropic/components":
|
|
3614
|
-
"@sidecar-ai/anthropic/hooks":
|
|
3615
|
-
"@sidecar-ai/anthropic/mcp":
|
|
3616
|
-
"@sidecar-ai/anthropic/plugin":
|
|
3617
|
-
"@sidecar-ai/anthropic/skill":
|
|
3289
|
+
"sidecar-ai": path17.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
3290
|
+
"@sidecar-ai/auth": path17.join(repoRoot, "packages", "auth", "src", "index.ts"),
|
|
3291
|
+
"@sidecar-ai/core": path17.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
3292
|
+
"@sidecar-ai/server": path17.join(repoRoot, "packages", "server", "src", "index.ts"),
|
|
3293
|
+
"@sidecar-ai/server/proxy": path17.join(repoRoot, "packages", "server", "src", "proxy.ts"),
|
|
3294
|
+
"@sidecar-ai/client": path17.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
3295
|
+
"@sidecar-ai/react": path17.join(repoRoot, "packages", "react", "src", "index.ts"),
|
|
3296
|
+
"@sidecar-ai/native": path17.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
3297
|
+
"@sidecar-ai/native/components": path17.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
3298
|
+
"@sidecar-ai/openai": path17.join(repoRoot, "packages", "openai", "src", "index.ts"),
|
|
3299
|
+
"@sidecar-ai/openai/components": path17.join(repoRoot, "packages", "openai", "src", "components.tsx"),
|
|
3300
|
+
"@sidecar-ai/openai/official": path17.join(repoRoot, "packages", "openai", "src", "official.ts"),
|
|
3301
|
+
"@sidecar-ai/anthropic": path17.join(repoRoot, "packages", "anthropic", "src", "index.ts"),
|
|
3302
|
+
"@sidecar-ai/anthropic/agent": path17.join(repoRoot, "packages", "anthropic", "src", "agent.ts"),
|
|
3303
|
+
"@sidecar-ai/anthropic/command": path17.join(repoRoot, "packages", "anthropic", "src", "command.ts"),
|
|
3304
|
+
"@sidecar-ai/anthropic/components": path17.join(repoRoot, "packages", "anthropic", "src", "components.tsx"),
|
|
3305
|
+
"@sidecar-ai/anthropic/hooks": path17.join(repoRoot, "packages", "anthropic", "src", "hooks.ts"),
|
|
3306
|
+
"@sidecar-ai/anthropic/mcp": path17.join(repoRoot, "packages", "anthropic", "src", "mcp.ts"),
|
|
3307
|
+
"@sidecar-ai/anthropic/plugin": path17.join(repoRoot, "packages", "anthropic", "src", "plugin.ts"),
|
|
3308
|
+
"@sidecar-ai/anthropic/skill": path17.join(repoRoot, "packages", "anthropic", "src", "skill.ts")
|
|
3618
3309
|
};
|
|
3619
3310
|
}
|
|
3620
3311
|
function findSidecarRepoRoot2(startDir) {
|
|
3621
|
-
let current =
|
|
3312
|
+
let current = path17.resolve(startDir);
|
|
3622
3313
|
while (true) {
|
|
3623
|
-
if (
|
|
3314
|
+
if (existsSync5(path17.join(current, "packages", "core", "src", "index.ts"))) {
|
|
3624
3315
|
return current;
|
|
3625
3316
|
}
|
|
3626
|
-
const parent =
|
|
3317
|
+
const parent = path17.dirname(current);
|
|
3627
3318
|
if (parent === current) {
|
|
3628
3319
|
return void 0;
|
|
3629
3320
|
}
|
|
@@ -3633,7 +3324,7 @@ function findSidecarRepoRoot2(startDir) {
|
|
|
3633
3324
|
|
|
3634
3325
|
// packages/compiler/src/build.ts
|
|
3635
3326
|
async function buildProject(options) {
|
|
3636
|
-
const rootDir =
|
|
3327
|
+
const rootDir = path18.resolve(options.rootDir);
|
|
3637
3328
|
const config = analyzeProjectConfig(rootDir);
|
|
3638
3329
|
const target = options.target ?? config.build.target ?? "mcp";
|
|
3639
3330
|
const host = options.host ?? config.build.host ?? "node";
|
|
@@ -3655,7 +3346,7 @@ async function buildProject(options) {
|
|
|
3655
3346
|
}
|
|
3656
3347
|
const outDir = resolveInsideRoot(rootDir, options.outDir ?? config.build.outDir ?? defaultBuildOutDir(host, target));
|
|
3657
3348
|
const runtimeOutDir = resolveRuntimeOutputDir(outDir, host);
|
|
3658
|
-
await buildWidgets(rootDir, runtimeOutDir, tools
|
|
3349
|
+
await buildWidgets(rootDir, runtimeOutDir, tools);
|
|
3659
3350
|
const manifest = {
|
|
3660
3351
|
version: 1,
|
|
3661
3352
|
target,
|
|
@@ -3671,11 +3362,11 @@ async function buildProject(options) {
|
|
|
3671
3362
|
};
|
|
3672
3363
|
await mkdir9(runtimeOutDir, { recursive: true });
|
|
3673
3364
|
await writeFile9(
|
|
3674
|
-
|
|
3365
|
+
path18.join(runtimeOutDir, "manifest.sidecar.json"),
|
|
3675
3366
|
`${JSON.stringify(manifest, null, 2)}
|
|
3676
3367
|
`
|
|
3677
3368
|
);
|
|
3678
|
-
await writeFile9(
|
|
3369
|
+
await writeFile9(path18.join(runtimeOutDir, "README.md"), renderMcpReadme(manifest));
|
|
3679
3370
|
await writeGeneratedTypes(rootDir, tools);
|
|
3680
3371
|
await buildServerOutput(rootDir, runtimeOutDir, manifest, identity, host, {
|
|
3681
3372
|
vercelOutputDir: outDir
|
|
@@ -3693,23 +3384,23 @@ function defaultBuildOutDir(host, target) {
|
|
|
3693
3384
|
}
|
|
3694
3385
|
function resolveRuntimeOutputDir(outDir, host) {
|
|
3695
3386
|
if (host === "vercel") {
|
|
3696
|
-
return
|
|
3387
|
+
return path18.join(outDir, VERCEL_FUNCTION_DIR);
|
|
3697
3388
|
}
|
|
3698
3389
|
return outDir;
|
|
3699
3390
|
}
|
|
3700
3391
|
function resolvePluginOutputBase(rootDir, outDir, host) {
|
|
3701
3392
|
if (host === "vercel" && isVercelBuildOutputDir(outDir)) {
|
|
3702
|
-
return
|
|
3393
|
+
return path18.join(rootDir, "out");
|
|
3703
3394
|
}
|
|
3704
|
-
return
|
|
3395
|
+
return path18.dirname(outDir);
|
|
3705
3396
|
}
|
|
3706
3397
|
function isVercelBuildOutputDir(outDir) {
|
|
3707
|
-
return
|
|
3398
|
+
return path18.basename(outDir) === "output" && path18.basename(path18.dirname(outDir)) === ".vercel";
|
|
3708
3399
|
}
|
|
3709
3400
|
function resolveInsideRoot(rootDir, output) {
|
|
3710
|
-
const resolved =
|
|
3711
|
-
const relative =
|
|
3712
|
-
if (relative.startsWith("..") ||
|
|
3401
|
+
const resolved = path18.resolve(rootDir, output);
|
|
3402
|
+
const relative = path18.relative(rootDir, resolved);
|
|
3403
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative)) {
|
|
3713
3404
|
throw new Error(`Build output must stay inside the project root: ${output}`);
|
|
3714
3405
|
}
|
|
3715
3406
|
return resolved;
|
|
@@ -4064,7 +3755,7 @@ var SidecarMcpServer = class {
|
|
|
4064
3755
|
/** Returns the server-chosen page size for all built-in list pagination. */
|
|
4065
3756
|
pageSize() {
|
|
4066
3757
|
const configured = this.options.pagination?.pageSize;
|
|
4067
|
-
return configured && configured > 0 ? Math.floor(configured) :
|
|
3758
|
+
return configured && configured > 0 ? Math.floor(configured) : 10;
|
|
4068
3759
|
}
|
|
4069
3760
|
/** Executes a tool after request-level and tool-level auth checks. */
|
|
4070
3761
|
async callTool(request, context) {
|
|
@@ -4173,7 +3864,6 @@ var SidecarMcpServer = class {
|
|
|
4173
3864
|
});
|
|
4174
3865
|
}
|
|
4175
3866
|
return {
|
|
4176
|
-
_meta: resource._meta,
|
|
4177
3867
|
contents: [
|
|
4178
3868
|
{
|
|
4179
3869
|
uri,
|
|
@@ -4273,11 +3963,6 @@ function createSidecarHttpHandler(options) {
|
|
|
4273
3963
|
const streamHub = createSseHub();
|
|
4274
3964
|
const mcp = createSidecarMcpServer(options);
|
|
4275
3965
|
return async (request, response) => {
|
|
4276
|
-
const pathname = request.url?.split("?")[0];
|
|
4277
|
-
const requestLog = createHttpRequestLog(request, pathname);
|
|
4278
|
-
response.once("finish", () => {
|
|
4279
|
-
logHttpRequest(requestLog, response.statusCode);
|
|
4280
|
-
});
|
|
4281
3966
|
if (isRejectedOrigin(request, options.allowedOrigins)) {
|
|
4282
3967
|
response.writeHead(403, { "content-type": "application/json" });
|
|
4283
3968
|
response.end(JSON.stringify({ error: "forbidden_origin" }));
|
|
@@ -4289,17 +3974,16 @@ function createSidecarHttpHandler(options) {
|
|
|
4289
3974
|
response.end(proxyResult.body ?? "");
|
|
4290
3975
|
return;
|
|
4291
3976
|
}
|
|
3977
|
+
const pathname = request.url?.split("?")[0];
|
|
4292
3978
|
if (options.auth && request.method === "GET" && isProtectedResourceMetadataPath(pathname, endpoint)) {
|
|
4293
3979
|
response.writeHead(200, { "content-type": "application/json" });
|
|
4294
3980
|
response.end(JSON.stringify(options.auth.metadata()));
|
|
4295
3981
|
return;
|
|
4296
3982
|
}
|
|
4297
|
-
if (options.auth && request.method === "GET" && pathname === "/.well-known/oauth-authorization-server") {
|
|
4298
|
-
await proxyAuthorizationServerMetadata(options.auth, response);
|
|
4299
|
-
return;
|
|
4300
|
-
}
|
|
4301
3983
|
if (request.method === "GET" && pathname === endpoint) {
|
|
4302
3984
|
try {
|
|
3985
|
+
validateProtocolVersion(request);
|
|
3986
|
+
validateGetHeaders(request);
|
|
4303
3987
|
const fetchRequest = toFetchRequest(request, options.publicUrl ?? options.auth?.resource);
|
|
4304
3988
|
if (options.auth) {
|
|
4305
3989
|
const authSession = await authorizeHttpRequest(options.auth, fetchRequest, response);
|
|
@@ -4307,8 +3991,6 @@ function createSidecarHttpHandler(options) {
|
|
|
4307
3991
|
return;
|
|
4308
3992
|
}
|
|
4309
3993
|
}
|
|
4310
|
-
validateProtocolVersion(request);
|
|
4311
|
-
validateGetHeaders(request);
|
|
4312
3994
|
streamHub.open(response);
|
|
4313
3995
|
} catch (error) {
|
|
4314
3996
|
const status = error instanceof JsonRpcHttpError ? error.status : 400;
|
|
@@ -4337,11 +4019,6 @@ function createSidecarHttpHandler(options) {
|
|
|
4337
4019
|
return;
|
|
4338
4020
|
}
|
|
4339
4021
|
try {
|
|
4340
|
-
const fetchRequest = toFetchRequest(request, options.publicUrl ?? options.auth?.resource);
|
|
4341
|
-
const authSession = options.auth ? await authorizeHttpRequest(options.auth, fetchRequest, response) : void 0;
|
|
4342
|
-
if (options.auth && authSession === AUTH_RESPONSE_SENT) {
|
|
4343
|
-
return;
|
|
4344
|
-
}
|
|
4345
4022
|
validateProtocolVersion(request);
|
|
4346
4023
|
validatePostHeaders(request);
|
|
4347
4024
|
const body = await readJson(request, maxBodyBytes);
|
|
@@ -4354,6 +4031,11 @@ function createSidecarHttpHandler(options) {
|
|
|
4354
4031
|
return;
|
|
4355
4032
|
}
|
|
4356
4033
|
const rpcRequest = assertJsonRpcRequest(body);
|
|
4034
|
+
const fetchRequest = toFetchRequest(request, options.publicUrl ?? options.auth?.resource);
|
|
4035
|
+
const authSession = options.auth ? await authorizeHttpRequest(options.auth, fetchRequest, response) : void 0;
|
|
4036
|
+
if (options.auth && authSession === AUTH_RESPONSE_SENT) {
|
|
4037
|
+
return;
|
|
4038
|
+
}
|
|
4357
4039
|
if (rpcRequest.id !== void 0 && hasProgressToken(rpcRequest)) {
|
|
4358
4040
|
const stream = createSseStream(response, { supportsRequestProgress: true });
|
|
4359
4041
|
const payload2 = await mcp.handle(rpcRequest, {
|
|
@@ -4445,73 +4127,6 @@ function escapeRegExp(value) {
|
|
|
4445
4127
|
function isProtectedResourceMetadataPath(pathname, endpoint) {
|
|
4446
4128
|
return pathname === "/.well-known/oauth-protected-resource" || pathname === `/.well-known/oauth-protected-resource${endpoint}`;
|
|
4447
4129
|
}
|
|
4448
|
-
function createHttpRequestLog(request, pathname) {
|
|
4449
|
-
return {
|
|
4450
|
-
method: request.method,
|
|
4451
|
-
path: pathname,
|
|
4452
|
-
host: truncateHeader(singleHeader(request.headers.host)),
|
|
4453
|
-
accept: truncateHeader(singleHeader(request.headers.accept)),
|
|
4454
|
-
contentType: truncateHeader(singleHeader(request.headers["content-type"])),
|
|
4455
|
-
contentLength: truncateHeader(singleHeader(request.headers["content-length"])),
|
|
4456
|
-
mcpProtocolVersion: truncateHeader(singleHeader(request.headers["mcp-protocol-version"])),
|
|
4457
|
-
origin: truncateHeader(singleHeader(request.headers.origin)),
|
|
4458
|
-
userAgent: truncateHeader(singleHeader(request.headers["user-agent"])),
|
|
4459
|
-
authorization: request.headers.authorization ? "present" : "absent",
|
|
4460
|
-
cookie: request.headers.cookie ? "present" : "absent"
|
|
4461
|
-
};
|
|
4462
|
-
}
|
|
4463
|
-
function logHttpRequest(metadata, status) {
|
|
4464
|
-
const debug = process.env.SIDECAR_DEBUG === "1" || process.env.SIDECAR_LOG_LEVEL === "debug";
|
|
4465
|
-
if (!debug && status < 400) {
|
|
4466
|
-
return;
|
|
4467
|
-
}
|
|
4468
|
-
const message = JSON.stringify({
|
|
4469
|
-
event: "sidecar.mcp.http",
|
|
4470
|
-
status,
|
|
4471
|
-
...stripUndefined4(metadata)
|
|
4472
|
-
});
|
|
4473
|
-
if (status >= 500) {
|
|
4474
|
-
console.error(message);
|
|
4475
|
-
} else if (status >= 400) {
|
|
4476
|
-
console.warn(message);
|
|
4477
|
-
} else {
|
|
4478
|
-
console.info(message);
|
|
4479
|
-
}
|
|
4480
|
-
}
|
|
4481
|
-
function singleHeader(value) {
|
|
4482
|
-
return Array.isArray(value) ? value.join(", ") : value;
|
|
4483
|
-
}
|
|
4484
|
-
function truncateHeader(value) {
|
|
4485
|
-
if (!value) {
|
|
4486
|
-
return void 0;
|
|
4487
|
-
}
|
|
4488
|
-
return value.length > 240 ? `${value.slice(0, 237)}...` : value;
|
|
4489
|
-
}
|
|
4490
|
-
async function proxyAuthorizationServerMetadata(auth, response) {
|
|
4491
|
-
const [authorizationServer] = auth.authorizationServers;
|
|
4492
|
-
if (!authorizationServer) {
|
|
4493
|
-
response.writeHead(404, { "content-type": "application/json" });
|
|
4494
|
-
response.end(JSON.stringify({ error: "authorization_server_not_configured" }));
|
|
4495
|
-
return;
|
|
4496
|
-
}
|
|
4497
|
-
try {
|
|
4498
|
-
const url = new URL("/.well-known/oauth-authorization-server", authorizationServer);
|
|
4499
|
-
const upstream = await fetch(url, { headers: { accept: "application/json" } });
|
|
4500
|
-
const body = await upstream.text();
|
|
4501
|
-
response.writeHead(upstream.ok ? 200 : 502, {
|
|
4502
|
-
"content-type": upstream.headers.get("content-type") ?? "application/json"
|
|
4503
|
-
});
|
|
4504
|
-
response.end(body);
|
|
4505
|
-
} catch (error) {
|
|
4506
|
-
console.warn(JSON.stringify({
|
|
4507
|
-
event: "sidecar.mcp.authorization_metadata_proxy_failed",
|
|
4508
|
-
authorizationServer,
|
|
4509
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
4510
|
-
}));
|
|
4511
|
-
response.writeHead(502, { "content-type": "application/json" });
|
|
4512
|
-
response.end(JSON.stringify({ error: "authorization_metadata_unavailable" }));
|
|
4513
|
-
}
|
|
4514
|
-
}
|
|
4515
4130
|
var JsonRpcError = class extends Error {
|
|
4516
4131
|
constructor(code, message, data) {
|
|
4517
4132
|
super(message);
|
|
@@ -4861,44 +4476,44 @@ function validateAgainstSchema(schema, value, message, options = {}) {
|
|
|
4861
4476
|
}
|
|
4862
4477
|
return value;
|
|
4863
4478
|
}
|
|
4864
|
-
function schemaFailure(schema, value,
|
|
4865
|
-
if (schema.anyOf?.length && !schema.anyOf.some((entry) => !schemaFailure(entry, value,
|
|
4866
|
-
return `${
|
|
4479
|
+
function schemaFailure(schema, value, path20) {
|
|
4480
|
+
if (schema.anyOf?.length && !schema.anyOf.some((entry) => !schemaFailure(entry, value, path20))) {
|
|
4481
|
+
return `${path20} must match one anyOf schema.`;
|
|
4867
4482
|
}
|
|
4868
|
-
if (schema.oneOf?.length && schema.oneOf.filter((entry) => !schemaFailure(entry, value,
|
|
4869
|
-
return `${
|
|
4483
|
+
if (schema.oneOf?.length && schema.oneOf.filter((entry) => !schemaFailure(entry, value, path20)).length !== 1) {
|
|
4484
|
+
return `${path20} must match exactly one oneOf schema.`;
|
|
4870
4485
|
}
|
|
4871
4486
|
if (schema.allOf?.length) {
|
|
4872
4487
|
for (const entry of schema.allOf) {
|
|
4873
|
-
const failure = schemaFailure(entry, value,
|
|
4488
|
+
const failure = schemaFailure(entry, value, path20);
|
|
4874
4489
|
if (failure) return failure;
|
|
4875
4490
|
}
|
|
4876
4491
|
}
|
|
4877
4492
|
if (schema.const !== void 0 && value !== schema.const) {
|
|
4878
|
-
return `${
|
|
4493
|
+
return `${path20} must equal ${JSON.stringify(schema.const)}.`;
|
|
4879
4494
|
}
|
|
4880
4495
|
if (schema.enum && !schema.enum.some((entry) => JSON.stringify(entry) === JSON.stringify(value))) {
|
|
4881
|
-
return `${
|
|
4496
|
+
return `${path20} must be one of the declared enum values.`;
|
|
4882
4497
|
}
|
|
4883
4498
|
if (schema.type) {
|
|
4884
4499
|
const types = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
4885
4500
|
if (!types.some((type) => matchesJsonSchemaType(type, value))) {
|
|
4886
|
-
return `${
|
|
4501
|
+
return `${path20} must be ${types.join(" or ")}.`;
|
|
4887
4502
|
}
|
|
4888
4503
|
}
|
|
4889
4504
|
if (schema.type === "object" || schema.properties || schema.required) {
|
|
4890
4505
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4891
|
-
return `${
|
|
4506
|
+
return `${path20} must be an object.`;
|
|
4892
4507
|
}
|
|
4893
4508
|
const record = value;
|
|
4894
4509
|
for (const required of schema.required ?? []) {
|
|
4895
4510
|
if (!(required in record)) {
|
|
4896
|
-
return `${
|
|
4511
|
+
return `${path20}.${required} is required.`;
|
|
4897
4512
|
}
|
|
4898
4513
|
}
|
|
4899
4514
|
for (const [key, propertySchema] of Object.entries(schema.properties ?? {})) {
|
|
4900
4515
|
if (key in record) {
|
|
4901
|
-
const failure = schemaFailure(propertySchema, record[key], `${
|
|
4516
|
+
const failure = schemaFailure(propertySchema, record[key], `${path20}.${key}`);
|
|
4902
4517
|
if (failure) return failure;
|
|
4903
4518
|
}
|
|
4904
4519
|
}
|
|
@@ -4906,12 +4521,12 @@ function schemaFailure(schema, value, path21) {
|
|
|
4906
4521
|
if (schema.additionalProperties === false) {
|
|
4907
4522
|
const extra = Object.keys(record).find((key) => !allowed.has(key));
|
|
4908
4523
|
if (extra) {
|
|
4909
|
-
return `${
|
|
4524
|
+
return `${path20}.${extra} is not allowed.`;
|
|
4910
4525
|
}
|
|
4911
4526
|
} else if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
4912
4527
|
for (const [key, entry] of Object.entries(record)) {
|
|
4913
4528
|
if (!allowed.has(key)) {
|
|
4914
|
-
const failure = schemaFailure(schema.additionalProperties, entry, `${
|
|
4529
|
+
const failure = schemaFailure(schema.additionalProperties, entry, `${path20}.${key}`);
|
|
4915
4530
|
if (failure) return failure;
|
|
4916
4531
|
}
|
|
4917
4532
|
}
|
|
@@ -4919,38 +4534,29 @@ function schemaFailure(schema, value, path21) {
|
|
|
4919
4534
|
}
|
|
4920
4535
|
if (schema.type === "array" || schema.items) {
|
|
4921
4536
|
if (!Array.isArray(value)) {
|
|
4922
|
-
return `${
|
|
4923
|
-
}
|
|
4924
|
-
if (schema.minItems !== void 0 && value.length < schema.minItems) {
|
|
4925
|
-
return `${path21} must contain at least ${schema.minItems} items.`;
|
|
4926
|
-
}
|
|
4927
|
-
if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
|
|
4928
|
-
return `${path21} must contain at most ${schema.maxItems} items.`;
|
|
4537
|
+
return `${path20} must be an array.`;
|
|
4929
4538
|
}
|
|
4930
4539
|
if (schema.items) {
|
|
4931
4540
|
for (const [index, entry] of value.entries()) {
|
|
4932
|
-
const failure = schemaFailure(schema.items, entry, `${
|
|
4541
|
+
const failure = schemaFailure(schema.items, entry, `${path20}[${index}]`);
|
|
4933
4542
|
if (failure) return failure;
|
|
4934
4543
|
}
|
|
4935
4544
|
}
|
|
4936
4545
|
}
|
|
4937
4546
|
if (typeof value === "string") {
|
|
4938
4547
|
if (schema.minLength !== void 0 && value.length < schema.minLength) {
|
|
4939
|
-
return `${
|
|
4548
|
+
return `${path20} is shorter than ${schema.minLength}.`;
|
|
4940
4549
|
}
|
|
4941
4550
|
if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
|
|
4942
|
-
return `${
|
|
4943
|
-
}
|
|
4944
|
-
if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
|
|
4945
|
-
return `${path21} must match pattern ${schema.pattern}.`;
|
|
4551
|
+
return `${path20} is longer than ${schema.maxLength}.`;
|
|
4946
4552
|
}
|
|
4947
4553
|
}
|
|
4948
4554
|
if (typeof value === "number") {
|
|
4949
4555
|
if (schema.minimum !== void 0 && value < schema.minimum) {
|
|
4950
|
-
return `${
|
|
4556
|
+
return `${path20} is less than ${schema.minimum}.`;
|
|
4951
4557
|
}
|
|
4952
4558
|
if (schema.maximum !== void 0 && value > schema.maximum) {
|
|
4953
|
-
return `${
|
|
4559
|
+
return `${path20} is greater than ${schema.maximum}.`;
|
|
4954
4560
|
}
|
|
4955
4561
|
}
|
|
4956
4562
|
return void 0;
|
|
@@ -5128,11 +4734,11 @@ import { stdin, stdout } from "process";
|
|
|
5128
4734
|
async function startTunnel(options) {
|
|
5129
4735
|
const provider = await resolveProvider(options.provider);
|
|
5130
4736
|
const localUrl = `http://127.0.0.1:${options.port}`;
|
|
5131
|
-
const
|
|
4737
|
+
const path20 = options.path ?? "/mcp";
|
|
5132
4738
|
if (provider === "cloudflared") {
|
|
5133
|
-
return startCloudflared(localUrl,
|
|
4739
|
+
return startCloudflared(localUrl, path20, options.timeoutMs);
|
|
5134
4740
|
}
|
|
5135
|
-
return startWrangler(localUrl,
|
|
4741
|
+
return startWrangler(localUrl, path20, options.timeoutMs);
|
|
5136
4742
|
}
|
|
5137
4743
|
async function validateTunnelEndpoint(options) {
|
|
5138
4744
|
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
@@ -5256,7 +4862,7 @@ function assertNpxAvailable() {
|
|
|
5256
4862
|
throw new Error(tunnelInstallMessage("wrangler"));
|
|
5257
4863
|
}
|
|
5258
4864
|
}
|
|
5259
|
-
async function startCloudflared(localUrl,
|
|
4865
|
+
async function startCloudflared(localUrl, path20, timeoutMs = 2e4) {
|
|
5260
4866
|
const child = spawn("cloudflared", ["tunnel", "--url", localUrl, "--no-autoupdate"], {
|
|
5261
4867
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5262
4868
|
});
|
|
@@ -5264,13 +4870,13 @@ async function startCloudflared(localUrl, path21, timeoutMs = 2e4) {
|
|
|
5264
4870
|
return {
|
|
5265
4871
|
provider: "cloudflared",
|
|
5266
4872
|
publicUrl,
|
|
5267
|
-
mcpUrl: appendPath(publicUrl,
|
|
4873
|
+
mcpUrl: appendPath(publicUrl, path20),
|
|
5268
4874
|
close() {
|
|
5269
4875
|
child.kill("SIGTERM");
|
|
5270
4876
|
}
|
|
5271
4877
|
};
|
|
5272
4878
|
}
|
|
5273
|
-
async function startWrangler(localUrl,
|
|
4879
|
+
async function startWrangler(localUrl, path20, timeoutMs = 2e4) {
|
|
5274
4880
|
const child = spawn("npx", ["--yes", "wrangler", "tunnel", "quick-start", localUrl], {
|
|
5275
4881
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5276
4882
|
});
|
|
@@ -5278,7 +4884,7 @@ async function startWrangler(localUrl, path21, timeoutMs = 2e4) {
|
|
|
5278
4884
|
return {
|
|
5279
4885
|
provider: "wrangler",
|
|
5280
4886
|
publicUrl,
|
|
5281
|
-
mcpUrl: appendPath(publicUrl,
|
|
4887
|
+
mcpUrl: appendPath(publicUrl, path20),
|
|
5282
4888
|
close() {
|
|
5283
4889
|
child.kill("SIGTERM");
|
|
5284
4890
|
}
|
|
@@ -5539,8 +5145,8 @@ function runInherited(command, args) {
|
|
|
5539
5145
|
});
|
|
5540
5146
|
});
|
|
5541
5147
|
}
|
|
5542
|
-
function appendPath(origin,
|
|
5543
|
-
return `${origin.replace(/\/+$/, "")}/${
|
|
5148
|
+
function appendPath(origin, path20) {
|
|
5149
|
+
return `${origin.replace(/\/+$/, "")}/${path20.replace(/^\/+/, "")}`;
|
|
5544
5150
|
}
|
|
5545
5151
|
function isRecord3(value) {
|
|
5546
5152
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -5568,9 +5174,9 @@ async function main(argv) {
|
|
|
5568
5174
|
);
|
|
5569
5175
|
console.log(`Host runtime: ${manifest.host}`);
|
|
5570
5176
|
if (manifest.host === "vercel") {
|
|
5571
|
-
console.log(`Vercel MCP function: ${
|
|
5177
|
+
console.log(`Vercel MCP function: ${path19.join(resolvedOutDir, VERCEL_ENTRYPOINT)}`);
|
|
5572
5178
|
} else {
|
|
5573
|
-
console.log(`Hostable MCP server: ${
|
|
5179
|
+
console.log(`Hostable MCP server: ${path19.join(resolvedOutDir, SERVER_ENTRYPOINT)}`);
|
|
5574
5180
|
}
|
|
5575
5181
|
if (plugins ?? manifest.config.build.plugins) {
|
|
5576
5182
|
console.log("Built claude-plugin package.");
|
|
@@ -5756,8 +5362,8 @@ function readOptionalPlugins(argv) {
|
|
|
5756
5362
|
return void 0;
|
|
5757
5363
|
}
|
|
5758
5364
|
async function previewComponents(options) {
|
|
5759
|
-
const cliDir =
|
|
5760
|
-
const css = await readFile8(
|
|
5365
|
+
const cliDir = path19.dirname(fileURLToPath(import.meta.url));
|
|
5366
|
+
const css = await readFile8(path19.join(cliDir, "../../native/src/styles.css"), "utf8").catch(() => readFile8(path19.join(process.cwd(), "packages/native/src/styles.css"), "utf8")).catch(() => "");
|
|
5761
5367
|
const html = renderComponentPreviewHtml(
|
|
5762
5368
|
options.host,
|
|
5763
5369
|
options.compare,
|
|
@@ -5797,10 +5403,10 @@ async function previewComponents(options) {
|
|
|
5797
5403
|
server.close();
|
|
5798
5404
|
}
|
|
5799
5405
|
async function writeComponentApproval(rootDir, approval) {
|
|
5800
|
-
const dir =
|
|
5406
|
+
const dir = path19.join(rootDir, ".sidecar", "approvals");
|
|
5801
5407
|
await mkdir10(dir, { recursive: true });
|
|
5802
5408
|
await writeFile10(
|
|
5803
|
-
|
|
5409
|
+
path19.join(dir, `components.${approval.host}.json`),
|
|
5804
5410
|
`${JSON.stringify(approval, null, 2)}
|
|
5805
5411
|
`
|
|
5806
5412
|
);
|
|
@@ -6152,71 +5758,71 @@ function printDiagnostics(diagnostics) {
|
|
|
6152
5758
|
}
|
|
6153
5759
|
}
|
|
6154
5760
|
async function loadRuntimeAuth(rootDir) {
|
|
6155
|
-
const authPath =
|
|
6156
|
-
if (!
|
|
5761
|
+
const authPath = path19.join(rootDir, "auth.ts");
|
|
5762
|
+
if (!existsSync6(authPath)) {
|
|
6157
5763
|
return void 0;
|
|
6158
5764
|
}
|
|
6159
|
-
const parentURL =
|
|
6160
|
-
const tsconfigPath =
|
|
6161
|
-
const tsconfig =
|
|
6162
|
-
const module = await
|
|
5765
|
+
const parentURL = pathToFileURL(path19.join(rootDir, "sidecar.config.ts")).href;
|
|
5766
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5767
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
5768
|
+
const module = await tsImport(pathToFileURL(authPath).href, {
|
|
6163
5769
|
parentURL,
|
|
6164
5770
|
tsconfig
|
|
6165
5771
|
});
|
|
6166
|
-
const defaultExport =
|
|
5772
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6167
5773
|
if (!isSidecarAuth(defaultExport)) {
|
|
6168
5774
|
throw new Error("auth.ts must default-export auth({ ... }) from sidecar-ai.");
|
|
6169
5775
|
}
|
|
6170
5776
|
return defaultExport;
|
|
6171
5777
|
}
|
|
6172
5778
|
async function loadRuntimeProxy(rootDir) {
|
|
6173
|
-
const proxyPath =
|
|
6174
|
-
if (!
|
|
5779
|
+
const proxyPath = path19.join(rootDir, "proxy.ts");
|
|
5780
|
+
if (!existsSync6(proxyPath)) {
|
|
6175
5781
|
return void 0;
|
|
6176
5782
|
}
|
|
6177
|
-
const parentURL =
|
|
6178
|
-
const tsconfigPath =
|
|
6179
|
-
const tsconfig =
|
|
6180
|
-
const module = await
|
|
5783
|
+
const parentURL = pathToFileURL(path19.join(rootDir, "sidecar.config.ts")).href;
|
|
5784
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5785
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
5786
|
+
const module = await tsImport(pathToFileURL(proxyPath).href, {
|
|
6181
5787
|
parentURL,
|
|
6182
5788
|
tsconfig
|
|
6183
5789
|
});
|
|
6184
|
-
const defaultExport =
|
|
5790
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6185
5791
|
if (!isSidecarProxy(defaultExport)) {
|
|
6186
5792
|
throw new Error("proxy.ts must default-export proxy({ ... }) from @sidecar-ai/server/proxy.");
|
|
6187
5793
|
}
|
|
6188
5794
|
return defaultExport;
|
|
6189
5795
|
}
|
|
6190
5796
|
async function loadRuntimeConfig(rootDir) {
|
|
6191
|
-
const configPath =
|
|
6192
|
-
if (!
|
|
5797
|
+
const configPath = path19.join(rootDir, "sidecar.config.ts");
|
|
5798
|
+
if (!existsSync6(configPath)) {
|
|
6193
5799
|
return void 0;
|
|
6194
5800
|
}
|
|
6195
|
-
const parentURL =
|
|
6196
|
-
const tsconfigPath =
|
|
6197
|
-
const tsconfig =
|
|
6198
|
-
const module = await
|
|
5801
|
+
const parentURL = pathToFileURL(configPath).href;
|
|
5802
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5803
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
5804
|
+
const module = await tsImport(pathToFileURL(configPath).href, {
|
|
6199
5805
|
parentURL,
|
|
6200
5806
|
tsconfig
|
|
6201
5807
|
});
|
|
6202
|
-
const defaultExport =
|
|
5808
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6203
5809
|
if (!defaultExport || typeof defaultExport !== "object") {
|
|
6204
5810
|
throw new Error("sidecar.config.ts must default-export defineConfig({ ... }) from sidecar-ai.");
|
|
6205
5811
|
}
|
|
6206
5812
|
return defaultExport;
|
|
6207
5813
|
}
|
|
6208
5814
|
async function loadRuntimeTools(rootDir, entries) {
|
|
6209
|
-
const parentURL =
|
|
6210
|
-
const tsconfigPath =
|
|
6211
|
-
const tsconfig =
|
|
5815
|
+
const parentURL = pathToFileURL(path19.join(rootDir, "sidecar.config.ts")).href;
|
|
5816
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5817
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
6212
5818
|
const loaded = [];
|
|
6213
5819
|
for (const entry of entries) {
|
|
6214
|
-
const sourcePath =
|
|
6215
|
-
const module = await
|
|
5820
|
+
const sourcePath = path19.join(rootDir, entry.sourceFile);
|
|
5821
|
+
const module = await tsImport(pathToFileURL(sourcePath).href, {
|
|
6216
5822
|
parentURL,
|
|
6217
5823
|
tsconfig
|
|
6218
5824
|
});
|
|
6219
|
-
const defaultExport =
|
|
5825
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6220
5826
|
if (!isSidecarTool(defaultExport)) {
|
|
6221
5827
|
throw new Error(`${entry.sourceFile} did not default-export a Sidecar tool.`);
|
|
6222
5828
|
}
|
|
@@ -6243,7 +5849,7 @@ async function loadResources(rootDir, outDir, manifest) {
|
|
|
6243
5849
|
if (!entry.widget?.outputFile) {
|
|
6244
5850
|
continue;
|
|
6245
5851
|
}
|
|
6246
|
-
const text = await readFile8(
|
|
5852
|
+
const text = await readFile8(path19.join(rootDir, outDir, entry.widget.outputFile), "utf8");
|
|
6247
5853
|
resources.push({
|
|
6248
5854
|
uri: entry.widget.resourceUri,
|
|
6249
5855
|
name: entry.name,
|
|
@@ -6253,16 +5859,16 @@ async function loadResources(rootDir, outDir, manifest) {
|
|
|
6253
5859
|
_meta: entry.widget.resourceMeta
|
|
6254
5860
|
});
|
|
6255
5861
|
}
|
|
6256
|
-
const parentURL =
|
|
6257
|
-
const tsconfigPath =
|
|
6258
|
-
const tsconfig =
|
|
5862
|
+
const parentURL = pathToFileURL(path19.join(rootDir, "sidecar.config.ts")).href;
|
|
5863
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5864
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
6259
5865
|
for (const entry of manifest.resources) {
|
|
6260
|
-
const sourcePath =
|
|
6261
|
-
const module = await
|
|
5866
|
+
const sourcePath = path19.join(rootDir, entry.sourceFile);
|
|
5867
|
+
const module = await tsImport(pathToFileURL(sourcePath).href, {
|
|
6262
5868
|
parentURL,
|
|
6263
5869
|
tsconfig
|
|
6264
5870
|
});
|
|
6265
|
-
const defaultExport =
|
|
5871
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6266
5872
|
if (!isSidecarResource(defaultExport)) {
|
|
6267
5873
|
throw new Error(`${entry.sourceFile} did not default-export a Sidecar resource.`);
|
|
6268
5874
|
}
|
|
@@ -6275,17 +5881,17 @@ async function loadResources(rootDir, outDir, manifest) {
|
|
|
6275
5881
|
return resources;
|
|
6276
5882
|
}
|
|
6277
5883
|
async function loadRuntimePrompts(rootDir, manifest) {
|
|
6278
|
-
const parentURL =
|
|
6279
|
-
const tsconfigPath =
|
|
6280
|
-
const tsconfig =
|
|
5884
|
+
const parentURL = pathToFileURL(path19.join(rootDir, "sidecar.config.ts")).href;
|
|
5885
|
+
const tsconfigPath = path19.join(rootDir, "tsconfig.json");
|
|
5886
|
+
const tsconfig = existsSync6(tsconfigPath) ? tsconfigPath : false;
|
|
6281
5887
|
const loaded = [];
|
|
6282
5888
|
for (const entry of manifest.prompts) {
|
|
6283
|
-
const sourcePath =
|
|
6284
|
-
const module = await
|
|
5889
|
+
const sourcePath = path19.join(rootDir, entry.sourceFile);
|
|
5890
|
+
const module = await tsImport(pathToFileURL(sourcePath).href, {
|
|
6285
5891
|
parentURL,
|
|
6286
5892
|
tsconfig
|
|
6287
5893
|
});
|
|
6288
|
-
const defaultExport =
|
|
5894
|
+
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
6289
5895
|
if (!isSidecarPrompt(defaultExport)) {
|
|
6290
5896
|
throw new Error(`${entry.sourceFile} did not default-export a Sidecar prompt.`);
|
|
6291
5897
|
}
|
|
@@ -6296,9 +5902,9 @@ async function loadRuntimePrompts(rootDir, manifest) {
|
|
|
6296
5902
|
}
|
|
6297
5903
|
return loaded;
|
|
6298
5904
|
}
|
|
6299
|
-
function
|
|
6300
|
-
if (value && typeof value === "object" && "default" in value && Object.keys(value).
|
|
6301
|
-
return
|
|
5905
|
+
function unwrapRuntimeDefault(value) {
|
|
5906
|
+
if (value && typeof value === "object" && "default" in value && Object.keys(value).length === 1) {
|
|
5907
|
+
return unwrapRuntimeDefault(value.default);
|
|
6302
5908
|
}
|
|
6303
5909
|
return value;
|
|
6304
5910
|
}
|
|
@@ -6332,7 +5938,7 @@ function isDirectRun() {
|
|
|
6332
5938
|
return false;
|
|
6333
5939
|
}
|
|
6334
5940
|
const entryPath = realpathSync.native(entry);
|
|
6335
|
-
return import.meta.url ===
|
|
5941
|
+
return import.meta.url === pathToFileURL(entryPath).href;
|
|
6336
5942
|
}
|
|
6337
5943
|
if (isDirectRun()) {
|
|
6338
5944
|
main(process.argv).catch((error) => {
|