@sidecar-ai/compiler 0.1.0-alpha.10 → 0.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -15
- package/dist/index.js +299 -678
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
// packages/core/src/index.ts
|
|
2
|
-
var toolBrand = /* @__PURE__ */ Symbol.for("sidecar.tool");
|
|
3
2
|
var toolResultBrand = /* @__PURE__ */ Symbol.for("sidecar.toolResult");
|
|
4
3
|
var resourceResultBrand = /* @__PURE__ */ Symbol.for("sidecar.resourceResult");
|
|
5
|
-
function isSidecarTool(value) {
|
|
6
|
-
return Boolean(
|
|
7
|
-
value && typeof value === "object" && (value[toolBrand] || value.kind === "sidecar.tool")
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
4
|
var toolResult = Object.assign(
|
|
11
5
|
createToolResult,
|
|
12
6
|
{
|
|
@@ -33,9 +27,9 @@ var resourceResult = Object.assign(
|
|
|
33
27
|
);
|
|
34
28
|
function createToolResult(input) {
|
|
35
29
|
const resultEnvelope = stripUndefined({
|
|
36
|
-
structuredContent:
|
|
30
|
+
structuredContent: input.structuredContent,
|
|
37
31
|
content: normalizeRequiredContent(input.content),
|
|
38
|
-
_meta:
|
|
32
|
+
_meta: input.meta,
|
|
39
33
|
isError: input.isError
|
|
40
34
|
});
|
|
41
35
|
Object.defineProperty(resultEnvelope, toolResultBrand, {
|
|
@@ -277,24 +271,10 @@ function isReadonlyArray(value) {
|
|
|
277
271
|
function stripUndefined(value) {
|
|
278
272
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
279
273
|
}
|
|
280
|
-
function stripJsonUndefined(value) {
|
|
281
|
-
if (value === void 0) {
|
|
282
|
-
return void 0;
|
|
283
|
-
}
|
|
284
|
-
if (Array.isArray(value)) {
|
|
285
|
-
return value.map((entry) => stripJsonUndefined(entry)).filter((entry) => entry !== void 0);
|
|
286
|
-
}
|
|
287
|
-
if (!value || typeof value !== "object") {
|
|
288
|
-
return value;
|
|
289
|
-
}
|
|
290
|
-
return Object.fromEntries(
|
|
291
|
-
Object.entries(value).map(([key, entry]) => [key, stripJsonUndefined(entry)]).filter(([, entry]) => entry !== void 0)
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
274
|
|
|
295
275
|
// packages/compiler/src/analyze.ts
|
|
296
276
|
import { readdir } from "fs/promises";
|
|
297
|
-
import
|
|
277
|
+
import path4 from "path";
|
|
298
278
|
import {
|
|
299
279
|
Node as Node4,
|
|
300
280
|
SyntaxKind as SyntaxKind2
|
|
@@ -461,7 +441,14 @@ function devSidecarTypePaths() {
|
|
|
461
441
|
import {
|
|
462
442
|
Node as Node2
|
|
463
443
|
} from "ts-morph";
|
|
464
|
-
function getParamsSchema(
|
|
444
|
+
function getParamsSchema(definition, execute) {
|
|
445
|
+
const explicitParams = definition.getProperty("params");
|
|
446
|
+
if (explicitParams && Node2.isPropertyAssignment(explicitParams)) {
|
|
447
|
+
const inferred = getSchemaFromZodProperty(explicitParams);
|
|
448
|
+
if (inferred) {
|
|
449
|
+
return inferred;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
465
452
|
const [params] = execute.getParameters();
|
|
466
453
|
if (!params) {
|
|
467
454
|
return emptyObjectSchema();
|
|
@@ -482,6 +469,74 @@ function getOutputSchema(definition, execute) {
|
|
|
482
469
|
}
|
|
483
470
|
return typeToJsonSchema(returnType);
|
|
484
471
|
}
|
|
472
|
+
function getSchemaFromZodProperty(property) {
|
|
473
|
+
const initializer = property.getInitializer();
|
|
474
|
+
if (!initializer) {
|
|
475
|
+
return void 0;
|
|
476
|
+
}
|
|
477
|
+
if (Node2.isCallExpression(initializer) && initializer.getExpression().getText().endsWith(".object")) {
|
|
478
|
+
const [shape] = initializer.getArguments();
|
|
479
|
+
if (shape && Node2.isObjectLiteralExpression(shape)) {
|
|
480
|
+
return zodObjectLiteralToSchema(shape);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return void 0;
|
|
484
|
+
}
|
|
485
|
+
function zodObjectLiteralToSchema(shape) {
|
|
486
|
+
const properties = {};
|
|
487
|
+
const required = [];
|
|
488
|
+
for (const property of shape.getProperties()) {
|
|
489
|
+
if (!Node2.isPropertyAssignment(property)) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
const name = property.getName().replace(/^["']|["']$/g, "");
|
|
493
|
+
const initializer = property.getInitializer();
|
|
494
|
+
if (!initializer) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
const propertySchema = zodExpressionToSchema(initializer);
|
|
498
|
+
properties[name] = propertySchema.schema;
|
|
499
|
+
if (!propertySchema.optional) {
|
|
500
|
+
required.push(name);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
type: "object",
|
|
505
|
+
properties,
|
|
506
|
+
required,
|
|
507
|
+
additionalProperties: false
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function zodExpressionToSchema(expression) {
|
|
511
|
+
const text = expression.getText();
|
|
512
|
+
const optional = /\.optional\(\)/.test(text) || /\.default\(/.test(text);
|
|
513
|
+
const schema = {};
|
|
514
|
+
if (/z\.string\(\)/.test(text)) {
|
|
515
|
+
schema.type = "string";
|
|
516
|
+
} else if (/z\.number\(\)/.test(text)) {
|
|
517
|
+
schema.type = "number";
|
|
518
|
+
} else if (/z\.boolean\(\)/.test(text)) {
|
|
519
|
+
schema.type = "boolean";
|
|
520
|
+
} else if (/z\.array\(/.test(text)) {
|
|
521
|
+
schema.type = "array";
|
|
522
|
+
schema.items = {};
|
|
523
|
+
} else {
|
|
524
|
+
schema.type = "object";
|
|
525
|
+
}
|
|
526
|
+
const min = text.match(/\.min\((\d+)/);
|
|
527
|
+
const max = text.match(/\.max\((\d+)/);
|
|
528
|
+
if (schema.type === "string") {
|
|
529
|
+
if (min) schema.minLength = Number(min[1]);
|
|
530
|
+
if (max) schema.maxLength = Number(max[1]);
|
|
531
|
+
} else {
|
|
532
|
+
if (min) schema.minimum = Number(min[1]);
|
|
533
|
+
if (max) schema.maximum = Number(max[1]);
|
|
534
|
+
}
|
|
535
|
+
if (/\.int\(\)/.test(text)) {
|
|
536
|
+
schema.type = "integer";
|
|
537
|
+
}
|
|
538
|
+
return { schema, optional };
|
|
539
|
+
}
|
|
485
540
|
function typeToJsonSchema(type, description) {
|
|
486
541
|
const withoutUndefined = removeUndefined(type);
|
|
487
542
|
const schema = typeToJsonSchemaInner(withoutUndefined);
|
|
@@ -627,103 +682,11 @@ function schemaDescription(symbol) {
|
|
|
627
682
|
}).find((comment) => comment.trim().length > 0);
|
|
628
683
|
}
|
|
629
684
|
|
|
630
|
-
// packages/compiler/src/runtime-schema.ts
|
|
631
|
-
import { existsSync as existsSync2 } from "fs";
|
|
632
|
-
import path3 from "path";
|
|
633
|
-
import { pathToFileURL } from "url";
|
|
634
|
-
import { tsImport } from "tsx/esm/api";
|
|
635
|
-
async function readRuntimeToolInputSchema(rootDir, sourcePath) {
|
|
636
|
-
let sidecarTool;
|
|
637
|
-
try {
|
|
638
|
-
sidecarTool = await importRuntimeTool(rootDir, sourcePath);
|
|
639
|
-
} catch (error) {
|
|
640
|
-
warnRuntimeSchemaFallback(sourcePath, error);
|
|
641
|
-
return void 0;
|
|
642
|
-
}
|
|
643
|
-
if (!sidecarTool.params) {
|
|
644
|
-
return void 0;
|
|
645
|
-
}
|
|
646
|
-
try {
|
|
647
|
-
return await paramsToJsonSchema(sidecarTool.params);
|
|
648
|
-
} catch (error) {
|
|
649
|
-
warnRuntimeSchemaFallback(sourcePath, error);
|
|
650
|
-
return void 0;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
async function importRuntimeTool(rootDir, sourcePath) {
|
|
654
|
-
const module = await tsImport(pathToFileURL(sourcePath).href, {
|
|
655
|
-
parentURL: runtimeParentUrl(rootDir),
|
|
656
|
-
tsconfig: runtimeTsconfig(rootDir)
|
|
657
|
-
});
|
|
658
|
-
const defaultExport = unwrapRuntimeDefault(module.default);
|
|
659
|
-
if (!isSidecarTool(defaultExport)) {
|
|
660
|
-
throw new Error(`${path3.relative(rootDir, sourcePath)} must default-export tool({ ... }).`);
|
|
661
|
-
}
|
|
662
|
-
return defaultExport;
|
|
663
|
-
}
|
|
664
|
-
async function paramsToJsonSchema(params) {
|
|
665
|
-
const instanceConverter = readInstanceConverter(params);
|
|
666
|
-
if (instanceConverter) {
|
|
667
|
-
return ensureJsonSchema(instanceConverter({ io: "input" }));
|
|
668
|
-
}
|
|
669
|
-
if (isZodMiniSchema(params)) {
|
|
670
|
-
const zod = await import("zod/v4-mini");
|
|
671
|
-
if (typeof zod.toJSONSchema === "function") {
|
|
672
|
-
return ensureJsonSchema(zod.toJSONSchema(params, { io: "input" }));
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
return void 0;
|
|
676
|
-
}
|
|
677
|
-
function readInstanceConverter(params) {
|
|
678
|
-
if (!params || typeof params !== "object") {
|
|
679
|
-
return void 0;
|
|
680
|
-
}
|
|
681
|
-
const record = params;
|
|
682
|
-
const converter = record.toJSONSchema ?? record.toJsonSchema;
|
|
683
|
-
return typeof converter === "function" ? converter.bind(params) : void 0;
|
|
684
|
-
}
|
|
685
|
-
function isZodMiniSchema(params) {
|
|
686
|
-
return Boolean(params && typeof params === "object" && "_zod" in params);
|
|
687
|
-
}
|
|
688
|
-
function ensureJsonSchema(value) {
|
|
689
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
690
|
-
return void 0;
|
|
691
|
-
}
|
|
692
|
-
return value;
|
|
693
|
-
}
|
|
694
|
-
function runtimeParentUrl(rootDir) {
|
|
695
|
-
const configPath = path3.join(rootDir, "sidecar.config.ts");
|
|
696
|
-
return pathToFileURL(existsSync2(configPath) ? configPath : rootDir).href;
|
|
697
|
-
}
|
|
698
|
-
function runtimeTsconfig(rootDir) {
|
|
699
|
-
const projectTsconfig = path3.join(rootDir, "tsconfig.json");
|
|
700
|
-
if (existsSync2(projectTsconfig)) {
|
|
701
|
-
return projectTsconfig;
|
|
702
|
-
}
|
|
703
|
-
const repoTsconfig = path3.join(process.cwd(), "tsconfig.json");
|
|
704
|
-
const repoCore = path3.join(process.cwd(), "packages", "core", "src", "index.ts");
|
|
705
|
-
return existsSyncSafe(repoTsconfig) && existsSyncSafe(repoCore) ? repoTsconfig : false;
|
|
706
|
-
}
|
|
707
|
-
function unwrapRuntimeDefault(value) {
|
|
708
|
-
if (value && typeof value === "object" && "default" in value && Object.keys(value).every((key) => key === "default" || key === "__esModule")) {
|
|
709
|
-
return unwrapRuntimeDefault(value.default);
|
|
710
|
-
}
|
|
711
|
-
return value;
|
|
712
|
-
}
|
|
713
|
-
function warnRuntimeSchemaFallback(sourcePath, error) {
|
|
714
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
715
|
-
console.warn(
|
|
716
|
-
`[sidecar] Could not convert runtime params schema for ${sourcePath}; falling back to TypeScript parameter inference. ${message}`
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
685
|
// packages/compiler/src/widgets.ts
|
|
721
686
|
import { createHash } from "crypto";
|
|
722
|
-
import { existsSync as
|
|
687
|
+
import { existsSync as existsSync2 } from "fs";
|
|
723
688
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
724
|
-
import
|
|
725
|
-
import path4 from "path";
|
|
726
|
-
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
689
|
+
import path3 from "path";
|
|
727
690
|
import { build as esbuild } from "esbuild";
|
|
728
691
|
import postcss from "postcss";
|
|
729
692
|
import {
|
|
@@ -731,30 +694,28 @@ import {
|
|
|
731
694
|
SyntaxKind
|
|
732
695
|
} from "ts-morph";
|
|
733
696
|
var CLAUDE_FONT_RESOURCE_DOMAIN = "https://assets.claude.ai";
|
|
734
|
-
|
|
735
|
-
async function buildWidgets(rootDir, outDir, tools, config = void 0) {
|
|
697
|
+
async function buildWidgets(rootDir, outDir, tools) {
|
|
736
698
|
const widgets = tools.filter(
|
|
737
699
|
(entry) => Boolean(entry.widget)
|
|
738
700
|
);
|
|
739
701
|
if (!widgets.length) {
|
|
740
702
|
return;
|
|
741
703
|
}
|
|
742
|
-
const cacheDir =
|
|
704
|
+
const cacheDir = path3.join(rootDir, ".sidecar", "cache", "widgets");
|
|
743
705
|
await mkdir(cacheDir, { recursive: true });
|
|
744
706
|
const appStyle = await prepareAppStyle(rootDir, cacheDir);
|
|
745
|
-
const configure = await loadWidgetBundlerHook(rootDir, cacheDir, config?.configure);
|
|
746
707
|
for (const entry of widgets) {
|
|
747
|
-
const sourceFile =
|
|
708
|
+
const sourceFile = path3.join(rootDir, entry.widget.sourceFile);
|
|
748
709
|
const safeId = safePathSegment(entry.id);
|
|
749
|
-
const entryFile =
|
|
750
|
-
const importPath = toImportSpecifier(
|
|
710
|
+
const entryFile = path3.join(cacheDir, `${safeId}.entry.tsx`);
|
|
711
|
+
const importPath = toImportSpecifier(path3.dirname(entryFile), sourceFile);
|
|
751
712
|
await writeFile(
|
|
752
713
|
entryFile,
|
|
753
714
|
`import React from "react";
|
|
754
715
|
import { createRoot } from "react-dom/client";
|
|
755
716
|
import { SidecarWidgetRoot } from "@sidecar-ai/react";
|
|
756
717
|
import "@sidecar-ai/native/styles.css";
|
|
757
|
-
${appStyle ? `import ${JSON.stringify(toImportSpecifier(
|
|
718
|
+
${appStyle ? `import ${JSON.stringify(toImportSpecifier(path3.dirname(entryFile), appStyle))};` : ""}
|
|
758
719
|
import Component from ${JSON.stringify(importPath)};
|
|
759
720
|
|
|
760
721
|
createRoot(document.getElementById("root")!).render(
|
|
@@ -762,219 +723,64 @@ createRoot(document.getElementById("root")!).render(
|
|
|
762
723
|
);
|
|
763
724
|
`
|
|
764
725
|
);
|
|
765
|
-
const
|
|
726
|
+
const bundled = await esbuild({
|
|
766
727
|
absWorkingDir: rootDir,
|
|
767
|
-
alias:
|
|
728
|
+
alias: devSidecarBundleAliases(rootDir),
|
|
768
729
|
bundle: true,
|
|
769
|
-
define: {
|
|
770
|
-
"process.env.NODE_ENV": JSON.stringify("production")
|
|
771
|
-
},
|
|
772
730
|
entryPoints: [entryFile],
|
|
773
731
|
format: "iife",
|
|
774
732
|
jsx: "automatic",
|
|
775
|
-
minify:
|
|
733
|
+
minify: false,
|
|
776
734
|
nodePaths: [
|
|
777
|
-
|
|
778
|
-
|
|
735
|
+
path3.join(rootDir, "node_modules"),
|
|
736
|
+
path3.join(process.cwd(), "node_modules")
|
|
779
737
|
],
|
|
780
738
|
outfile: "widget.js",
|
|
781
739
|
platform: "browser",
|
|
782
740
|
sourcemap: false,
|
|
783
741
|
write: false
|
|
784
742
|
});
|
|
785
|
-
const
|
|
786
|
-
const
|
|
787
|
-
rootDir,
|
|
788
|
-
outDir,
|
|
789
|
-
entryFile,
|
|
790
|
-
widget: {
|
|
791
|
-
toolId: entry.id,
|
|
792
|
-
toolName: entry.name,
|
|
793
|
-
target: entry.target,
|
|
794
|
-
sourceFile: entry.widget.sourceFile
|
|
795
|
-
},
|
|
796
|
-
esbuildOptions: mergeWidgetBuildOptions(baseOptions, staticOptions)
|
|
797
|
-
}) : void 0;
|
|
798
|
-
const bundled = await esbuild(enforceWidgetBuildInvariants(
|
|
799
|
-
mergeWidgetBuildOptions(baseOptions, staticOptions, configuredOptions),
|
|
800
|
-
{ rootDir, entryFile }
|
|
801
|
-
));
|
|
802
|
-
const outputFiles = bundled.outputFiles ?? [];
|
|
803
|
-
const javascript = outputFiles.find((file) => file.path.endsWith(".js"))?.text ?? "";
|
|
804
|
-
const css = outputFiles.filter((file) => file.path.endsWith(".css")).map((file) => file.text).join("\n");
|
|
743
|
+
const javascript = bundled.outputFiles.find((file) => file.path.endsWith(".js"))?.text ?? "";
|
|
744
|
+
const css = bundled.outputFiles.filter((file) => file.path.endsWith(".css")).map((file) => file.text).join("\n");
|
|
805
745
|
const html = renderWidgetHtml(entry.name, javascript, css);
|
|
806
746
|
const hash = createHash("sha256").update(html).digest("hex").slice(0, 12);
|
|
807
|
-
const outputDir =
|
|
808
|
-
const outputFile =
|
|
747
|
+
const outputDir = path3.join(outDir, "public", "widgets", safeId);
|
|
748
|
+
const outputFile = path3.join(outputDir, `widget.${hash}.html`);
|
|
809
749
|
const resourceUri = `ui://${safeId}/widget.${hash}.html`;
|
|
810
750
|
await mkdir(outputDir, { recursive: true });
|
|
811
751
|
await writeFile(outputFile, html);
|
|
812
752
|
entry.widget.resourceUri = resourceUri;
|
|
813
753
|
entry.widget.resourceMeta = widgetResourceMeta(entry.widget.options, entry.target);
|
|
814
|
-
entry.widget.outputFile =
|
|
754
|
+
entry.widget.outputFile = path3.relative(outDir, outputFile);
|
|
815
755
|
entry.descriptor._meta = mergeWidgetMeta(entry.descriptor._meta, widgetMeta(resourceUri, entry.widget.options, entry.target));
|
|
816
756
|
}
|
|
817
757
|
}
|
|
818
|
-
function widgetBuildOptionsFromConfig(rootDir, config) {
|
|
819
|
-
const esbuildConfig = config?.esbuild;
|
|
820
|
-
if (!esbuildConfig) {
|
|
821
|
-
return void 0;
|
|
822
|
-
}
|
|
823
|
-
return {
|
|
824
|
-
alias: normalizeAliases(rootDir, esbuildConfig.alias),
|
|
825
|
-
conditions: esbuildConfig.conditions,
|
|
826
|
-
define: esbuildConfig.define,
|
|
827
|
-
external: esbuildConfig.external,
|
|
828
|
-
jsx: esbuildConfig.jsx,
|
|
829
|
-
jsxImportSource: esbuildConfig.jsxImportSource,
|
|
830
|
-
loader: esbuildConfig.loader,
|
|
831
|
-
mainFields: esbuildConfig.mainFields
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
async function loadWidgetBundlerHook(rootDir, cacheDir, hookPath) {
|
|
835
|
-
if (!hookPath) {
|
|
836
|
-
return void 0;
|
|
837
|
-
}
|
|
838
|
-
const sourcePath = path4.resolve(rootDir, hookPath);
|
|
839
|
-
const relative = path4.relative(rootDir, sourcePath);
|
|
840
|
-
if (relative.startsWith("..") || path4.isAbsolute(relative)) {
|
|
841
|
-
throw new Error(`Widget bundler hook must stay inside the project root: ${hookPath}`);
|
|
842
|
-
}
|
|
843
|
-
if (!existsSync3(sourcePath)) {
|
|
844
|
-
throw new Error(`Widget bundler hook not found: ${hookPath}`);
|
|
845
|
-
}
|
|
846
|
-
const outputFile = path4.join(cacheDir, `widget-bundler.${contentHash(hookPath)}.mjs`);
|
|
847
|
-
await esbuild({
|
|
848
|
-
absWorkingDir: rootDir,
|
|
849
|
-
alias: devSidecarBundleAliases(rootDir),
|
|
850
|
-
bundle: true,
|
|
851
|
-
entryPoints: [sourcePath],
|
|
852
|
-
format: "esm",
|
|
853
|
-
nodePaths: [
|
|
854
|
-
path4.join(rootDir, "node_modules"),
|
|
855
|
-
path4.join(process.cwd(), "node_modules")
|
|
856
|
-
],
|
|
857
|
-
outfile: outputFile,
|
|
858
|
-
packages: "external",
|
|
859
|
-
platform: "node",
|
|
860
|
-
target: "node20"
|
|
861
|
-
});
|
|
862
|
-
const module = await import(`${pathToFileURL2(outputFile).href}?t=${Date.now()}`);
|
|
863
|
-
if (typeof module.default !== "function") {
|
|
864
|
-
throw new Error(`Widget bundler hook must default-export a function: ${hookPath}`);
|
|
865
|
-
}
|
|
866
|
-
return module.default;
|
|
867
|
-
}
|
|
868
|
-
async function configureWidgetBuild(hook, input) {
|
|
869
|
-
const result = await hook(input);
|
|
870
|
-
if (!result) {
|
|
871
|
-
return void 0;
|
|
872
|
-
}
|
|
873
|
-
if (typeof result === "object" && "esbuildOptions" in result) {
|
|
874
|
-
return result.esbuildOptions;
|
|
875
|
-
}
|
|
876
|
-
return result;
|
|
877
|
-
}
|
|
878
|
-
function mergeWidgetBuildOptions(...options) {
|
|
879
|
-
const merged = {};
|
|
880
|
-
for (const option of options) {
|
|
881
|
-
if (!option) {
|
|
882
|
-
continue;
|
|
883
|
-
}
|
|
884
|
-
const previousAlias = merged.alias;
|
|
885
|
-
const previousDefine = merged.define;
|
|
886
|
-
const previousLoader = merged.loader;
|
|
887
|
-
const previousExternal = merged.external;
|
|
888
|
-
const previousNodePaths = merged.nodePaths;
|
|
889
|
-
const previousPlugins = merged.plugins;
|
|
890
|
-
Object.assign(merged, option);
|
|
891
|
-
merged.alias = { ...previousAlias ?? {}, ...option.alias ?? {} };
|
|
892
|
-
merged.define = { ...previousDefine ?? {}, ...option.define ?? {} };
|
|
893
|
-
merged.loader = { ...previousLoader ?? {}, ...option.loader ?? {} };
|
|
894
|
-
merged.external = uniqueStrings([...previousExternal ?? [], ...option.external ?? []]);
|
|
895
|
-
merged.nodePaths = uniqueStrings([...previousNodePaths ?? [], ...option.nodePaths ?? []]);
|
|
896
|
-
merged.plugins = [...previousPlugins ?? [], ...option.plugins ?? []];
|
|
897
|
-
}
|
|
898
|
-
return merged;
|
|
899
|
-
}
|
|
900
|
-
function enforceWidgetBuildInvariants(options, required) {
|
|
901
|
-
const aliases = required ? { ...options.alias ?? {}, ...reactSingletonAliases(required.rootDir) } : options.alias;
|
|
902
|
-
return {
|
|
903
|
-
...options,
|
|
904
|
-
absWorkingDir: required?.rootDir ?? options.absWorkingDir,
|
|
905
|
-
alias: aliases,
|
|
906
|
-
bundle: true,
|
|
907
|
-
entryPoints: required ? [required.entryFile] : options.entryPoints,
|
|
908
|
-
format: "iife",
|
|
909
|
-
outfile: "widget.js",
|
|
910
|
-
platform: "browser",
|
|
911
|
-
write: false
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
function sidecarWidgetAliases(rootDir) {
|
|
915
|
-
return {
|
|
916
|
-
...devSidecarBundleAliases(rootDir) ?? {},
|
|
917
|
-
...reactSingletonAliases(rootDir)
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
function reactSingletonAliases(rootDir) {
|
|
921
|
-
return {
|
|
922
|
-
react: resolveProjectModule(rootDir, "react"),
|
|
923
|
-
"react/jsx-runtime": resolveProjectModule(rootDir, "react/jsx-runtime"),
|
|
924
|
-
"react/jsx-dev-runtime": resolveProjectModule(rootDir, "react/jsx-dev-runtime"),
|
|
925
|
-
"react-dom": resolveProjectModule(rootDir, "react-dom"),
|
|
926
|
-
"react-dom/client": resolveProjectModule(rootDir, "react-dom/client"),
|
|
927
|
-
"react-dom/server": resolveProjectModule(rootDir, "react-dom/server")
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
function resolveProjectModule(rootDir, specifier) {
|
|
931
|
-
return requireFromCompiler.resolve(specifier, {
|
|
932
|
-
paths: [rootDir, process.cwd()]
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
function normalizeAliases(rootDir, aliases) {
|
|
936
|
-
if (!aliases) {
|
|
937
|
-
return void 0;
|
|
938
|
-
}
|
|
939
|
-
return Object.fromEntries(
|
|
940
|
-
Object.entries(aliases).map(([key, value]) => [
|
|
941
|
-
key,
|
|
942
|
-
value.startsWith(".") ? path4.resolve(rootDir, value) : value
|
|
943
|
-
])
|
|
944
|
-
);
|
|
945
|
-
}
|
|
946
|
-
function uniqueStrings(values) {
|
|
947
|
-
return [...new Set(values)];
|
|
948
|
-
}
|
|
949
|
-
function contentHash(value) {
|
|
950
|
-
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
951
|
-
}
|
|
952
758
|
function devSidecarBundleAliases(rootDir) {
|
|
953
759
|
const repoRoot = findSidecarRepoRoot(rootDir) ?? findSidecarRepoRoot(process.cwd());
|
|
954
760
|
if (!repoRoot) {
|
|
955
761
|
return void 0;
|
|
956
762
|
}
|
|
957
|
-
const reactEntry =
|
|
958
|
-
if (!
|
|
763
|
+
const reactEntry = path3.join(repoRoot, "packages", "react", "src", "index.ts");
|
|
764
|
+
if (!existsSync2(reactEntry)) {
|
|
959
765
|
return void 0;
|
|
960
766
|
}
|
|
961
767
|
return {
|
|
962
|
-
"sidecar-ai":
|
|
963
|
-
"@sidecar-ai/client":
|
|
964
|
-
"@sidecar-ai/core":
|
|
768
|
+
"sidecar-ai": path3.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
769
|
+
"@sidecar-ai/client": path3.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
770
|
+
"@sidecar-ai/core": path3.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
965
771
|
"@sidecar-ai/react": reactEntry,
|
|
966
|
-
"@sidecar-ai/native":
|
|
967
|
-
"@sidecar-ai/native/components":
|
|
968
|
-
"@sidecar-ai/native/styles.css":
|
|
772
|
+
"@sidecar-ai/native": path3.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
773
|
+
"@sidecar-ai/native/components": path3.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
774
|
+
"@sidecar-ai/native/styles.css": path3.join(repoRoot, "packages", "native", "src", "styles.css")
|
|
969
775
|
};
|
|
970
776
|
}
|
|
971
777
|
function findSidecarRepoRoot(startDir) {
|
|
972
|
-
let current =
|
|
778
|
+
let current = path3.resolve(startDir);
|
|
973
779
|
while (true) {
|
|
974
|
-
if (
|
|
780
|
+
if (existsSync2(path3.join(current, "packages", "core", "src", "index.ts"))) {
|
|
975
781
|
return current;
|
|
976
782
|
}
|
|
977
|
-
const parent =
|
|
783
|
+
const parent = path3.dirname(current);
|
|
978
784
|
if (parent === current) {
|
|
979
785
|
return void 0;
|
|
980
786
|
}
|
|
@@ -982,13 +788,13 @@ function findSidecarRepoRoot(startDir) {
|
|
|
982
788
|
}
|
|
983
789
|
}
|
|
984
790
|
async function prepareAppStyle(rootDir, cacheDir) {
|
|
985
|
-
const sourceFile =
|
|
986
|
-
if (!
|
|
791
|
+
const sourceFile = path3.join(rootDir, "style.css");
|
|
792
|
+
if (!existsSync2(sourceFile)) {
|
|
987
793
|
return void 0;
|
|
988
794
|
}
|
|
989
795
|
const source = await readFile(sourceFile, "utf8");
|
|
990
796
|
const css = await processAppStyle(source, sourceFile);
|
|
991
|
-
const outputFile =
|
|
797
|
+
const outputFile = path3.join(cacheDir, "style.css");
|
|
992
798
|
await writeFile(outputFile, css);
|
|
993
799
|
return outputFile;
|
|
994
800
|
}
|
|
@@ -1000,7 +806,7 @@ async function processAppStyle(source, from) {
|
|
|
1000
806
|
const plugins = [];
|
|
1001
807
|
if (cssSource.includes("@tailwind")) {
|
|
1002
808
|
const tailwind = await import("@tailwindcss/postcss");
|
|
1003
|
-
plugins.push(tailwind.default({ base:
|
|
809
|
+
plugins.push(tailwind.default({ base: path3.dirname(from) }));
|
|
1004
810
|
}
|
|
1005
811
|
const autoprefixer = await import("autoprefixer");
|
|
1006
812
|
plugins.push(autoprefixer.default());
|
|
@@ -1014,13 +820,13 @@ function needsPostcss(source) {
|
|
|
1014
820
|
return /@import\s+["']tailwindcss["']|@tailwind|@source|@theme|@plugin/.test(source);
|
|
1015
821
|
}
|
|
1016
822
|
function findWidget(rootDir, toolFile, id, target = "mcp", toolVariant = "shared") {
|
|
1017
|
-
const selected = selectWidgetFile(
|
|
823
|
+
const selected = selectWidgetFile(path3.dirname(toolFile), target, toolVariant);
|
|
1018
824
|
if (!selected) {
|
|
1019
825
|
return void 0;
|
|
1020
826
|
}
|
|
1021
827
|
const safeId = safePathSegment(id);
|
|
1022
828
|
return {
|
|
1023
|
-
sourceFile:
|
|
829
|
+
sourceFile: path3.relative(rootDir, selected.filePath),
|
|
1024
830
|
variant: selected.variant,
|
|
1025
831
|
resourceUri: `ui://${safeId}/widget.html`
|
|
1026
832
|
};
|
|
@@ -1055,8 +861,7 @@ function widgetMeta(resourceUri, options = {}, target = "mcp") {
|
|
|
1055
861
|
const standard = {
|
|
1056
862
|
ui: {
|
|
1057
863
|
resourceUri
|
|
1058
|
-
}
|
|
1059
|
-
"ui/resourceUri": resourceUri
|
|
864
|
+
}
|
|
1060
865
|
};
|
|
1061
866
|
if (target !== "chatgpt") {
|
|
1062
867
|
return standard;
|
|
@@ -1203,17 +1008,17 @@ function readStringArrayProperty(definition, propertyName) {
|
|
|
1203
1008
|
}
|
|
1204
1009
|
function selectWidgetFile(directory, target, toolVariant) {
|
|
1205
1010
|
if (toolVariant === "openai") {
|
|
1206
|
-
const filePath =
|
|
1207
|
-
return
|
|
1011
|
+
const filePath = path3.join(directory, "widget.openai.tsx");
|
|
1012
|
+
return existsSync2(filePath) ? { filePath, variant: "openai" } : void 0;
|
|
1208
1013
|
}
|
|
1209
1014
|
if (toolVariant === "anthropic") {
|
|
1210
|
-
const filePath =
|
|
1211
|
-
return
|
|
1015
|
+
const filePath = path3.join(directory, "widget.anthropic.tsx");
|
|
1016
|
+
return existsSync2(filePath) ? { filePath, variant: "anthropic" } : void 0;
|
|
1212
1017
|
}
|
|
1213
1018
|
const candidates = target === "chatgpt" || target === "claude" || target === "mcp" ? [{ name: "widget.tsx", variant: "shared" }] : [];
|
|
1214
1019
|
for (const candidate of candidates) {
|
|
1215
|
-
const filePath =
|
|
1216
|
-
if (
|
|
1020
|
+
const filePath = path3.join(directory, candidate.name);
|
|
1021
|
+
if (existsSync2(filePath)) {
|
|
1217
1022
|
return { filePath, variant: candidate.variant };
|
|
1218
1023
|
}
|
|
1219
1024
|
}
|
|
@@ -1264,23 +1069,17 @@ function stripUndefined3(value) {
|
|
|
1264
1069
|
// packages/compiler/src/analyze.ts
|
|
1265
1070
|
async function analyzeProjectTools(rootDir, options = {}) {
|
|
1266
1071
|
const target = options.target ?? "mcp";
|
|
1267
|
-
const toolFiles = await findToolFiles(
|
|
1072
|
+
const toolFiles = await findToolFiles(path4.join(rootDir, "server"), target);
|
|
1268
1073
|
if (toolFiles.length === 0) {
|
|
1269
1074
|
return [];
|
|
1270
1075
|
}
|
|
1271
1076
|
const project = createProject(rootDir);
|
|
1272
1077
|
const authScopes = readAuthScopeCatalog(project, rootDir);
|
|
1273
|
-
|
|
1274
|
-
candidate,
|
|
1275
|
-
sourceFile: project.addSourceFileAtPath(candidate.filePath)
|
|
1276
|
-
}));
|
|
1277
|
-
const runtimeInputSchemas = await readRuntimeInputSchemas(rootDir, sources);
|
|
1278
|
-
return sources.map(
|
|
1279
|
-
({ candidate, sourceFile }) => analyzeToolFile(sourceFile, rootDir, {
|
|
1078
|
+
return toolFiles.map(
|
|
1079
|
+
(candidate) => analyzeToolFile(project.addSourceFileAtPath(candidate.filePath), rootDir, {
|
|
1280
1080
|
target,
|
|
1281
1081
|
variant: candidate.variant,
|
|
1282
|
-
authScopes
|
|
1283
|
-
inputSchema: runtimeInputSchemas.get(candidate.filePath)
|
|
1082
|
+
authScopes
|
|
1284
1083
|
})
|
|
1285
1084
|
);
|
|
1286
1085
|
}
|
|
@@ -1289,7 +1088,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1289
1088
|
const variant = options.variant ?? "shared";
|
|
1290
1089
|
const definition = findToolDefinition(sourceFile);
|
|
1291
1090
|
const absoluteFile = sourceFile.getFilePath();
|
|
1292
|
-
const directory =
|
|
1091
|
+
const directory = path4.basename(path4.dirname(absoluteFile));
|
|
1293
1092
|
const name = getRequiredStringProperty(definition, "name", sourceFile);
|
|
1294
1093
|
const id = getOptionalStringProperty(definition, "id") ?? toMachineName(directory);
|
|
1295
1094
|
const description = getRequiredStringProperty(
|
|
@@ -1302,7 +1101,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1302
1101
|
const hosts = readHosts(definition);
|
|
1303
1102
|
const auth = readAuthPolicy(definition, options.authScopes ?? {});
|
|
1304
1103
|
const execute = getExecuteFunction(definition, sourceFile);
|
|
1305
|
-
const inputSchema =
|
|
1104
|
+
const inputSchema = getParamsSchema(definition, execute);
|
|
1306
1105
|
const outputSchema = getOutputSchema(definition, execute);
|
|
1307
1106
|
const descriptor = createToolDescriptor({
|
|
1308
1107
|
name,
|
|
@@ -1320,7 +1119,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1320
1119
|
validateWidgetHierarchy(sourceFile, absoluteFile, target, variant);
|
|
1321
1120
|
const widget = findWidget(rootDir, absoluteFile, id, target, variant);
|
|
1322
1121
|
if (widget) {
|
|
1323
|
-
const widgetFile =
|
|
1122
|
+
const widgetFile = path4.join(rootDir, widget.sourceFile);
|
|
1324
1123
|
const project = sourceFile.getProject();
|
|
1325
1124
|
const widgetSourceFile = project.getSourceFile(widgetFile) ?? project.addSourceFileAtPath(widgetFile);
|
|
1326
1125
|
widget.options = {
|
|
@@ -1331,7 +1130,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1331
1130
|
descriptor._meta = mergeWidgetMeta(descriptor._meta, widgetMeta(widget.resourceUri, widget.options, target));
|
|
1332
1131
|
}
|
|
1333
1132
|
return {
|
|
1334
|
-
sourceFile:
|
|
1133
|
+
sourceFile: path4.relative(rootDir, absoluteFile),
|
|
1335
1134
|
variant,
|
|
1336
1135
|
target,
|
|
1337
1136
|
directory,
|
|
@@ -1346,26 +1145,6 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1346
1145
|
descriptor
|
|
1347
1146
|
};
|
|
1348
1147
|
}
|
|
1349
|
-
async function readRuntimeInputSchemas(rootDir, sources) {
|
|
1350
|
-
const schemas = /* @__PURE__ */ new Map();
|
|
1351
|
-
await Promise.all(sources.map(async ({ candidate, sourceFile }) => {
|
|
1352
|
-
const definition = findToolDefinition(sourceFile);
|
|
1353
|
-
if (!definitionHasRuntimeParams(definition)) {
|
|
1354
|
-
return;
|
|
1355
|
-
}
|
|
1356
|
-
const schema = await readRuntimeToolInputSchema(rootDir, candidate.filePath);
|
|
1357
|
-
if (schema) {
|
|
1358
|
-
schemas.set(candidate.filePath, schema);
|
|
1359
|
-
}
|
|
1360
|
-
}));
|
|
1361
|
-
return schemas;
|
|
1362
|
-
}
|
|
1363
|
-
function definitionHasRuntimeParams(definition) {
|
|
1364
|
-
if (definition.getProperty("params")) {
|
|
1365
|
-
return true;
|
|
1366
|
-
}
|
|
1367
|
-
return Boolean(getWithParamsCall(definition));
|
|
1368
|
-
}
|
|
1369
1148
|
function readAuthPolicy(definition, authScopes) {
|
|
1370
1149
|
const initializer = readObjectProperty2(definition, "auth");
|
|
1371
1150
|
if (!initializer) {
|
|
@@ -1382,7 +1161,7 @@ function readAuthPolicy(definition, authScopes) {
|
|
|
1382
1161
|
return { authenticated: true };
|
|
1383
1162
|
}
|
|
1384
1163
|
function readAuthScopeCatalog(project, rootDir) {
|
|
1385
|
-
const authPath =
|
|
1164
|
+
const authPath = path4.join(rootDir, "auth.ts");
|
|
1386
1165
|
if (!existsSyncSafe(authPath)) {
|
|
1387
1166
|
return {};
|
|
1388
1167
|
}
|
|
@@ -1464,12 +1243,12 @@ function isNamedCall(call, name) {
|
|
|
1464
1243
|
return callee === name || callee.endsWith(`.${name}`);
|
|
1465
1244
|
}
|
|
1466
1245
|
function validateWidgetHierarchy(sourceFile, toolFile, target, variant) {
|
|
1467
|
-
const directory =
|
|
1246
|
+
const directory = path4.dirname(toolFile);
|
|
1468
1247
|
const platformWidget = target === "chatgpt" ? "widget.openai.tsx" : target === "claude" ? "widget.anthropic.tsx" : void 0;
|
|
1469
1248
|
if (!platformWidget || variant !== "shared") {
|
|
1470
1249
|
return;
|
|
1471
1250
|
}
|
|
1472
|
-
if (existsSyncSafe(
|
|
1251
|
+
if (existsSyncSafe(path4.join(directory, platformWidget))) {
|
|
1473
1252
|
const expectedTool = target === "chatgpt" ? "tool.openai.ts" : "tool.anthropic.ts";
|
|
1474
1253
|
throw new CompilerError(
|
|
1475
1254
|
sourceFile,
|
|
@@ -1484,7 +1263,7 @@ async function findToolFiles(serverDir, target) {
|
|
|
1484
1263
|
const entries = await readdir(serverDir, { withFileTypes: true });
|
|
1485
1264
|
const files = [];
|
|
1486
1265
|
for (const entry of entries) {
|
|
1487
|
-
const entryPath =
|
|
1266
|
+
const entryPath = path4.join(serverDir, entry.name);
|
|
1488
1267
|
if (entry.isDirectory()) {
|
|
1489
1268
|
const candidate = selectToolFile(entryPath, target);
|
|
1490
1269
|
if (candidate) {
|
|
@@ -1503,7 +1282,7 @@ function selectToolFile(directory, target) {
|
|
|
1503
1282
|
{ name: "tool.ts", variant: "shared" }
|
|
1504
1283
|
] : [{ name: "tool.ts", variant: "shared" }];
|
|
1505
1284
|
for (const candidate of candidates) {
|
|
1506
|
-
const filePath =
|
|
1285
|
+
const filePath = path4.join(directory, candidate.name);
|
|
1507
1286
|
if (existsSyncSafe(filePath)) {
|
|
1508
1287
|
return { filePath, variant: candidate.variant };
|
|
1509
1288
|
}
|
|
@@ -1539,32 +1318,16 @@ function getExecuteFunction(definition, sourceFile) {
|
|
|
1539
1318
|
return property;
|
|
1540
1319
|
}
|
|
1541
1320
|
if (Node4.isPropertyAssignment(property)) {
|
|
1542
|
-
const initializer =
|
|
1321
|
+
const initializer = property.getInitializer();
|
|
1543
1322
|
if (initializer && (Node4.isArrowFunction(initializer) || Node4.isFunctionExpression(initializer))) {
|
|
1544
1323
|
return initializer;
|
|
1545
1324
|
}
|
|
1546
|
-
const withParamsCall = getWithParamsCall(definition);
|
|
1547
|
-
const wrappedExecute = unwrapExpression(withParamsCall?.getArguments()[1]);
|
|
1548
|
-
if (wrappedExecute && (Node4.isArrowFunction(wrappedExecute) || Node4.isFunctionExpression(wrappedExecute))) {
|
|
1549
|
-
return wrappedExecute;
|
|
1550
|
-
}
|
|
1551
1325
|
}
|
|
1552
1326
|
throw new CompilerError(
|
|
1553
1327
|
sourceFile,
|
|
1554
1328
|
"execute must be a method, function expression, or arrow function."
|
|
1555
1329
|
);
|
|
1556
1330
|
}
|
|
1557
|
-
function getWithParamsCall(definition) {
|
|
1558
|
-
const property = definition.getProperty("execute");
|
|
1559
|
-
if (!property || !Node4.isPropertyAssignment(property)) {
|
|
1560
|
-
return void 0;
|
|
1561
|
-
}
|
|
1562
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1563
|
-
if (!initializer || !Node4.isCallExpression(initializer)) {
|
|
1564
|
-
return void 0;
|
|
1565
|
-
}
|
|
1566
|
-
return isNamedCall(initializer, "withParams") ? initializer : void 0;
|
|
1567
|
-
}
|
|
1568
1331
|
function getRequiredStringProperty(definition, propertyName, sourceFile) {
|
|
1569
1332
|
const value = getOptionalStringProperty(definition, propertyName);
|
|
1570
1333
|
if (value === void 0 || !value.trim()) {
|
|
@@ -1720,16 +1483,16 @@ function readStringArrayProperty2(definition, propertyName) {
|
|
|
1720
1483
|
|
|
1721
1484
|
// packages/compiler/src/build.ts
|
|
1722
1485
|
import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
|
|
1723
|
-
import
|
|
1486
|
+
import path18 from "path";
|
|
1724
1487
|
|
|
1725
1488
|
// packages/compiler/src/config.ts
|
|
1726
|
-
import
|
|
1489
|
+
import path5 from "path";
|
|
1727
1490
|
import {
|
|
1728
1491
|
Node as Node5,
|
|
1729
1492
|
SyntaxKind as SyntaxKind3
|
|
1730
1493
|
} from "ts-morph";
|
|
1731
1494
|
function analyzeProjectConfig(rootDir) {
|
|
1732
|
-
const configPath =
|
|
1495
|
+
const configPath = path5.join(rootDir, "sidecar.config.ts");
|
|
1733
1496
|
if (!existsSyncSafe(configPath)) {
|
|
1734
1497
|
return defaultCompilerConfig();
|
|
1735
1498
|
}
|
|
@@ -1741,13 +1504,6 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1741
1504
|
return defaultCompilerConfig();
|
|
1742
1505
|
}
|
|
1743
1506
|
return {
|
|
1744
|
-
build: {
|
|
1745
|
-
target: readTargetNested(definition, "build", "target"),
|
|
1746
|
-
host: readHostNested(definition, "build", "host"),
|
|
1747
|
-
outDir: readStringNested(definition, "build", "outDir"),
|
|
1748
|
-
plugins: readBooleanNested(definition, "build", "plugins"),
|
|
1749
|
-
widgets: readWidgetBuildConfig(definition)
|
|
1750
|
-
},
|
|
1751
1507
|
resources: {
|
|
1752
1508
|
subscribe: readBooleanNested(definition, "resources", "subscribe") ?? false,
|
|
1753
1509
|
listChanged: readBooleanNested(definition, "resources", "listChanged") ?? false
|
|
@@ -1759,52 +1515,13 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1759
1515
|
listChanged: readBooleanNested(definition, "tools", "listChanged") ?? false
|
|
1760
1516
|
},
|
|
1761
1517
|
pagination: {
|
|
1762
|
-
pageSize: readNumberNested(definition, "pagination", "pageSize") ??
|
|
1518
|
+
pageSize: readNumberNested(definition, "pagination", "pageSize") ?? 10,
|
|
1763
1519
|
hasOverride: hasProperty(readObjectProperty3(definition, "pagination"), "override")
|
|
1764
1520
|
}
|
|
1765
1521
|
};
|
|
1766
1522
|
}
|
|
1767
|
-
function readWidgetBuildConfig(definition) {
|
|
1768
|
-
const widgets = readObjectProperty3(readObjectProperty3(definition, "build"), "widgets");
|
|
1769
|
-
if (!widgets) {
|
|
1770
|
-
return void 0;
|
|
1771
|
-
}
|
|
1772
|
-
const config = {};
|
|
1773
|
-
const configure = readStringProperty3(widgets, "configure");
|
|
1774
|
-
const esbuild3 = readWidgetEsbuildConfig(widgets);
|
|
1775
|
-
if (configure) config.configure = configure;
|
|
1776
|
-
if (esbuild3) config.esbuild = esbuild3;
|
|
1777
|
-
return Object.keys(config).length ? config : void 0;
|
|
1778
|
-
}
|
|
1779
|
-
function readWidgetEsbuildConfig(widgets) {
|
|
1780
|
-
const esbuild3 = readObjectProperty3(widgets, "esbuild");
|
|
1781
|
-
if (!esbuild3) {
|
|
1782
|
-
return void 0;
|
|
1783
|
-
}
|
|
1784
|
-
const config = {};
|
|
1785
|
-
const alias = readStringRecordProperty(esbuild3, "alias");
|
|
1786
|
-
const define = readStringRecordProperty(esbuild3, "define");
|
|
1787
|
-
const external = readStringArrayProperty3(esbuild3, "external");
|
|
1788
|
-
const loader = readStringRecordProperty(esbuild3, "loader");
|
|
1789
|
-
const conditions = readStringArrayProperty3(esbuild3, "conditions");
|
|
1790
|
-
const mainFields = readStringArrayProperty3(esbuild3, "mainFields");
|
|
1791
|
-
const jsx = readStringProperty3(esbuild3, "jsx");
|
|
1792
|
-
const jsxImportSource = readStringProperty3(esbuild3, "jsxImportSource");
|
|
1793
|
-
if (alias) config.alias = alias;
|
|
1794
|
-
if (define) config.define = define;
|
|
1795
|
-
if (external) config.external = external;
|
|
1796
|
-
if (loader) config.loader = loader;
|
|
1797
|
-
if (conditions) config.conditions = conditions;
|
|
1798
|
-
if (mainFields) config.mainFields = mainFields;
|
|
1799
|
-
if (jsx === "automatic" || jsx === "transform" || jsx === "preserve") {
|
|
1800
|
-
config.jsx = jsx;
|
|
1801
|
-
}
|
|
1802
|
-
if (jsxImportSource) config.jsxImportSource = jsxImportSource;
|
|
1803
|
-
return Object.keys(config).length ? config : void 0;
|
|
1804
|
-
}
|
|
1805
1523
|
function defaultCompilerConfig() {
|
|
1806
1524
|
return {
|
|
1807
|
-
build: {},
|
|
1808
1525
|
resources: {
|
|
1809
1526
|
subscribe: false,
|
|
1810
1527
|
listChanged: false
|
|
@@ -1816,26 +1533,11 @@ function defaultCompilerConfig() {
|
|
|
1816
1533
|
listChanged: false
|
|
1817
1534
|
},
|
|
1818
1535
|
pagination: {
|
|
1819
|
-
pageSize:
|
|
1536
|
+
pageSize: 10,
|
|
1820
1537
|
hasOverride: false
|
|
1821
1538
|
}
|
|
1822
1539
|
};
|
|
1823
1540
|
}
|
|
1824
|
-
function readTargetNested(definition, section, propertyName) {
|
|
1825
|
-
const value = readStringNested(definition, section, propertyName);
|
|
1826
|
-
return value === "mcp" || value === "chatgpt" || value === "claude" ? value : void 0;
|
|
1827
|
-
}
|
|
1828
|
-
function readHostNested(definition, section, propertyName) {
|
|
1829
|
-
const value = readStringNested(definition, section, propertyName);
|
|
1830
|
-
return value === "node" || value === "vercel" ? value : void 0;
|
|
1831
|
-
}
|
|
1832
|
-
function readStringNested(definition, section, propertyName) {
|
|
1833
|
-
const object = readObjectProperty3(definition, section);
|
|
1834
|
-
if (!object) {
|
|
1835
|
-
return void 0;
|
|
1836
|
-
}
|
|
1837
|
-
return readStringProperty3(object, propertyName);
|
|
1838
|
-
}
|
|
1839
1541
|
function readBooleanNested(definition, section, propertyName) {
|
|
1840
1542
|
const object = readObjectProperty3(definition, section);
|
|
1841
1543
|
if (!object) {
|
|
@@ -1866,9 +1568,6 @@ function readNumberNested(definition, section, propertyName) {
|
|
|
1866
1568
|
return initializer && Node5.isNumericLiteral(initializer) ? Number(initializer.getLiteralText()) : void 0;
|
|
1867
1569
|
}
|
|
1868
1570
|
function readObjectProperty3(definition, propertyName) {
|
|
1869
|
-
if (!definition) {
|
|
1870
|
-
return void 0;
|
|
1871
|
-
}
|
|
1872
1571
|
const property = definition.getProperty(propertyName);
|
|
1873
1572
|
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1874
1573
|
return void 0;
|
|
@@ -1876,79 +1575,38 @@ function readObjectProperty3(definition, propertyName) {
|
|
|
1876
1575
|
const initializer = unwrapExpression(property.getInitializer());
|
|
1877
1576
|
return initializer && Node5.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
1878
1577
|
}
|
|
1879
|
-
function readStringProperty3(definition, propertyName) {
|
|
1880
|
-
const property = definition.getProperty(propertyName);
|
|
1881
|
-
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1882
|
-
return void 0;
|
|
1883
|
-
}
|
|
1884
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1885
|
-
return initializer && Node5.isStringLiteral(initializer) ? initializer.getLiteralText() : void 0;
|
|
1886
|
-
}
|
|
1887
|
-
function readStringArrayProperty3(definition, propertyName) {
|
|
1888
|
-
const property = definition.getProperty(propertyName);
|
|
1889
|
-
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1890
|
-
return void 0;
|
|
1891
|
-
}
|
|
1892
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1893
|
-
if (!initializer || !Node5.isArrayLiteralExpression(initializer)) {
|
|
1894
|
-
return void 0;
|
|
1895
|
-
}
|
|
1896
|
-
const values = initializer.getElements().map((element) => {
|
|
1897
|
-
const unwrapped = unwrapExpression(element);
|
|
1898
|
-
return unwrapped && Node5.isStringLiteral(unwrapped) ? unwrapped.getLiteralText() : void 0;
|
|
1899
|
-
});
|
|
1900
|
-
return values.every((value) => value !== void 0) ? values : void 0;
|
|
1901
|
-
}
|
|
1902
|
-
function readStringRecordProperty(definition, propertyName) {
|
|
1903
|
-
const object = readObjectProperty3(definition, propertyName);
|
|
1904
|
-
if (!object) {
|
|
1905
|
-
return void 0;
|
|
1906
|
-
}
|
|
1907
|
-
const record = {};
|
|
1908
|
-
for (const property of object.getProperties()) {
|
|
1909
|
-
if (!Node5.isPropertyAssignment(property)) {
|
|
1910
|
-
return void 0;
|
|
1911
|
-
}
|
|
1912
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1913
|
-
if (!initializer || !Node5.isStringLiteral(initializer)) {
|
|
1914
|
-
return void 0;
|
|
1915
|
-
}
|
|
1916
|
-
record[property.getName().replace(/^["']|["']$/g, "")] = initializer.getLiteralText();
|
|
1917
|
-
}
|
|
1918
|
-
return record;
|
|
1919
|
-
}
|
|
1920
1578
|
function hasProperty(definition, propertyName) {
|
|
1921
1579
|
return Boolean(definition?.getProperty(propertyName));
|
|
1922
1580
|
}
|
|
1923
1581
|
|
|
1924
1582
|
// packages/compiler/src/diagnostics.ts
|
|
1925
|
-
import { existsSync as
|
|
1583
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1926
1584
|
import { readFile as readFile2 } from "fs/promises";
|
|
1927
|
-
import
|
|
1585
|
+
import path6 from "path";
|
|
1928
1586
|
async function collectProjectDiagnostics(rootDir, input) {
|
|
1929
1587
|
const diagnostics = [];
|
|
1930
1588
|
const tools = Array.isArray(input) ? input : input.tools;
|
|
1931
1589
|
const resources = Array.isArray(input) ? [] : input.resources ?? [];
|
|
1932
1590
|
const prompts = Array.isArray(input) ? [] : input.prompts ?? [];
|
|
1933
1591
|
const config = Array.isArray(input) ? void 0 : input.config;
|
|
1934
|
-
const hasAuthConfig =
|
|
1592
|
+
const hasAuthConfig = existsSync3(path6.join(rootDir, "auth.ts"));
|
|
1935
1593
|
for (const entry of tools) {
|
|
1936
|
-
const toolPath =
|
|
1594
|
+
const toolPath = path6.join(rootDir, entry.sourceFile);
|
|
1937
1595
|
const toolSource = await readFile2(toolPath, "utf8");
|
|
1938
|
-
diagnostics.push(...diagnoseToolSource(entry, toolSource, hasAuthConfig));
|
|
1596
|
+
diagnostics.push(...diagnoseToolSource(rootDir, entry, toolSource, hasAuthConfig));
|
|
1939
1597
|
if (entry.widget) {
|
|
1940
|
-
const widgetPath =
|
|
1598
|
+
const widgetPath = path6.join(rootDir, entry.widget.sourceFile);
|
|
1941
1599
|
const widgetSource = await readFile2(widgetPath, "utf8");
|
|
1942
1600
|
diagnostics.push(...diagnoseWidgetSource(rootDir, entry, widgetSource));
|
|
1943
1601
|
}
|
|
1944
1602
|
}
|
|
1945
1603
|
for (const entry of resources) {
|
|
1946
|
-
const resourcePath =
|
|
1604
|
+
const resourcePath = path6.join(rootDir, entry.sourceFile);
|
|
1947
1605
|
const resourceSource = await readFile2(resourcePath, "utf8");
|
|
1948
1606
|
diagnostics.push(...diagnoseResourceSource(entry, resourceSource));
|
|
1949
1607
|
}
|
|
1950
1608
|
for (const entry of prompts) {
|
|
1951
|
-
const promptPath =
|
|
1609
|
+
const promptPath = path6.join(rootDir, entry.sourceFile);
|
|
1952
1610
|
const promptSource = await readFile2(promptPath, "utf8");
|
|
1953
1611
|
diagnostics.push(...diagnosePromptSource(entry, promptSource));
|
|
1954
1612
|
}
|
|
@@ -1963,7 +1621,7 @@ function formatDiagnostic(diagnostic) {
|
|
|
1963
1621
|
hint: ${diagnostic.hint}` : "";
|
|
1964
1622
|
return `${location} - ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}${hint}`;
|
|
1965
1623
|
}
|
|
1966
|
-
function diagnoseToolSource(entry, source, hasAuthConfig) {
|
|
1624
|
+
function diagnoseToolSource(rootDir, entry, source, hasAuthConfig) {
|
|
1967
1625
|
const diagnostics = [];
|
|
1968
1626
|
const toolLocation = locate(source, "tool({");
|
|
1969
1627
|
if (!entry.description.trim().startsWith("Use this when")) {
|
|
@@ -2180,21 +1838,21 @@ function isIgnored(source, code) {
|
|
|
2180
1838
|
|
|
2181
1839
|
// packages/compiler/src/generated.ts
|
|
2182
1840
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
2183
|
-
import
|
|
1841
|
+
import path7 from "path";
|
|
2184
1842
|
async function writeGeneratedTypes(rootDir, tools) {
|
|
2185
|
-
const generatedDir =
|
|
1843
|
+
const generatedDir = path7.join(rootDir, ".sidecar", "generated");
|
|
2186
1844
|
await mkdir2(generatedDir, { recursive: true });
|
|
2187
1845
|
const appCallableTools = tools.filter(isAppCallable);
|
|
2188
1846
|
const methodNames = uniqueMethodNames(appCallableTools.map((entry) => toIdentifier(entry.id)));
|
|
2189
1847
|
const imports = appCallableTools.map(
|
|
2190
|
-
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir,
|
|
1848
|
+
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir, path7.join(rootDir, entry.sourceFile), { extension: "js" }))};`
|
|
2191
1849
|
).join("\n");
|
|
2192
1850
|
const ids = appCallableTools.map((entry, index) => ` ${methodNames[index]}: ${JSON.stringify(entry.id)}`).join(",\n");
|
|
2193
1851
|
const toolTypes = appCallableTools.map(
|
|
2194
|
-
(
|
|
1852
|
+
(entry, index) => ` ${methodNames[index]}(params: ToolParams<typeof tool${index}>): Promise<ToolOutput<typeof tool${index}>>;`
|
|
2195
1853
|
).join("\n");
|
|
2196
1854
|
await writeFile2(
|
|
2197
|
-
|
|
1855
|
+
path7.join(generatedDir, "tools.ts"),
|
|
2198
1856
|
`/**
|
|
2199
1857
|
* Generated Sidecar widget tool client.
|
|
2200
1858
|
*
|
|
@@ -2244,13 +1902,13 @@ function uniqueMethodNames(names) {
|
|
|
2244
1902
|
|
|
2245
1903
|
// packages/compiler/src/identity.ts
|
|
2246
1904
|
import { readFile as readFile3 } from "fs/promises";
|
|
2247
|
-
import
|
|
1905
|
+
import path8 from "path";
|
|
2248
1906
|
async function loadProjectIdentity(rootDir) {
|
|
2249
|
-
const packageJson = await readOptionalJson(
|
|
1907
|
+
const packageJson = await readOptionalJson(path8.join(rootDir, "package.json"));
|
|
2250
1908
|
const configText = await readOptionalText(
|
|
2251
|
-
|
|
1909
|
+
path8.join(rootDir, "sidecar.config.ts")
|
|
2252
1910
|
);
|
|
2253
|
-
const name = readConfigString(configText, "name") ?? packageJson?.name ??
|
|
1911
|
+
const name = readConfigString(configText, "name") ?? packageJson?.name ?? path8.basename(rootDir);
|
|
2254
1912
|
const version = readConfigString(configText, "version") ?? packageJson?.version ?? "0.0.0-dev";
|
|
2255
1913
|
const description = readConfigString(configText, "description") ?? packageJson?.description ?? `${name} Sidecar app.`;
|
|
2256
1914
|
return {
|
|
@@ -2284,32 +1942,32 @@ function readConfigString(configText, key) {
|
|
|
2284
1942
|
|
|
2285
1943
|
// packages/compiler/src/plugins.ts
|
|
2286
1944
|
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
2287
|
-
import
|
|
1945
|
+
import path14 from "path";
|
|
2288
1946
|
|
|
2289
1947
|
// packages/compiler/src/plugin-components/agents.ts
|
|
2290
1948
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
2291
|
-
import
|
|
1949
|
+
import path9 from "path";
|
|
2292
1950
|
async function emitClaudeAgents(rootDir, destination) {
|
|
2293
|
-
const source =
|
|
1951
|
+
const source = path9.join(rootDir, "agents");
|
|
2294
1952
|
if (!existsSyncSafe(source)) {
|
|
2295
1953
|
return;
|
|
2296
1954
|
}
|
|
2297
1955
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
2298
1956
|
const agentDirs = entries.filter(
|
|
2299
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
1957
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path9.join(source, entry.name, "agent.ts"))
|
|
2300
1958
|
);
|
|
2301
1959
|
if (!agentDirs.length) {
|
|
2302
1960
|
return;
|
|
2303
1961
|
}
|
|
2304
1962
|
await mkdir3(destination, { recursive: true });
|
|
2305
1963
|
for (const entry of agentDirs) {
|
|
2306
|
-
const sourceText = await readFile4(
|
|
1964
|
+
const sourceText = await readFile4(path9.join(source, entry.name, "agent.ts"), "utf8");
|
|
2307
1965
|
const markdown = parseClaudeAgent(
|
|
2308
1966
|
sourceText,
|
|
2309
1967
|
entry.name
|
|
2310
1968
|
);
|
|
2311
1969
|
const agentName = readObjectString(sourceText, "name") ?? entry.name;
|
|
2312
|
-
await writeFile3(
|
|
1970
|
+
await writeFile3(path9.join(destination, `${safeFileStem(agentName)}.md`), markdown);
|
|
2313
1971
|
}
|
|
2314
1972
|
}
|
|
2315
1973
|
function parseClaudeAgent(source, fallbackName) {
|
|
@@ -2338,41 +1996,41 @@ ${prompt.trim()}
|
|
|
2338
1996
|
|
|
2339
1997
|
// packages/compiler/src/plugin-components/commands.ts
|
|
2340
1998
|
import { cp, lstat, mkdir as mkdir4, readdir as readdir3, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
2341
|
-
import
|
|
1999
|
+
import path10 from "path";
|
|
2342
2000
|
async function copyCommands(rootDir, destination) {
|
|
2343
|
-
const source =
|
|
2001
|
+
const source = path10.join(rootDir, "commands");
|
|
2344
2002
|
if (!existsSyncSafe(source)) {
|
|
2345
2003
|
return;
|
|
2346
2004
|
}
|
|
2347
2005
|
await mkdir4(destination, { recursive: true });
|
|
2348
2006
|
const entries = await readdir3(source, { withFileTypes: true });
|
|
2349
2007
|
for (const entry of entries) {
|
|
2350
|
-
const sourcePath =
|
|
2008
|
+
const sourcePath = path10.join(source, entry.name);
|
|
2351
2009
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2352
2010
|
if (await safeCommandCopyFilter(sourcePath)) {
|
|
2353
|
-
await cp(sourcePath,
|
|
2011
|
+
await cp(sourcePath, path10.join(destination, safeFileStem(entry.name.replace(/\.md$/, "")) + ".md"));
|
|
2354
2012
|
}
|
|
2355
2013
|
continue;
|
|
2356
2014
|
}
|
|
2357
2015
|
if (!entry.isDirectory()) {
|
|
2358
2016
|
continue;
|
|
2359
2017
|
}
|
|
2360
|
-
const dynamicCommand =
|
|
2018
|
+
const dynamicCommand = path10.join(sourcePath, "command.ts");
|
|
2361
2019
|
if (existsSyncSafe(dynamicCommand)) {
|
|
2362
2020
|
const sourceText = await readFile5(dynamicCommand, "utf8");
|
|
2363
2021
|
const markdown = parseDynamicCommand(sourceText, entry.name);
|
|
2364
2022
|
const commandName = readObjectString(sourceText, "name") ?? entry.name;
|
|
2365
|
-
await writeFile4(
|
|
2023
|
+
await writeFile4(path10.join(destination, `${safeFileStem(commandName)}.md`), markdown);
|
|
2366
2024
|
continue;
|
|
2367
2025
|
}
|
|
2368
|
-
await cp(sourcePath,
|
|
2026
|
+
await cp(sourcePath, path10.join(destination, entry.name), {
|
|
2369
2027
|
recursive: true,
|
|
2370
2028
|
filter: safeCommandCopyFilter
|
|
2371
2029
|
});
|
|
2372
2030
|
}
|
|
2373
2031
|
}
|
|
2374
2032
|
async function safeCommandCopyFilter(sourcePath) {
|
|
2375
|
-
const basename =
|
|
2033
|
+
const basename = path10.basename(sourcePath);
|
|
2376
2034
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2377
2035
|
return false;
|
|
2378
2036
|
}
|
|
@@ -2401,32 +2059,32 @@ ${Object.entries(frontmatter).map(([key, value]) => `${key}: ${yamlScalar(value)
|
|
|
2401
2059
|
|
|
2402
2060
|
// packages/compiler/src/plugin-components/hooks.ts
|
|
2403
2061
|
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
2404
|
-
import
|
|
2062
|
+
import path11 from "path";
|
|
2405
2063
|
import {
|
|
2406
2064
|
Node as Node6,
|
|
2407
2065
|
Project as Project2,
|
|
2408
2066
|
SyntaxKind as SyntaxKind4
|
|
2409
2067
|
} from "ts-morph";
|
|
2410
2068
|
async function copyHooks(rootDir, destination) {
|
|
2411
|
-
const source =
|
|
2069
|
+
const source = path11.join(rootDir, "hooks");
|
|
2412
2070
|
if (!existsSyncSafe(source)) {
|
|
2413
2071
|
return;
|
|
2414
2072
|
}
|
|
2415
2073
|
const entries = await readdir4(source, { withFileTypes: true });
|
|
2416
2074
|
const hookDirs = entries.filter(
|
|
2417
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
2075
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path11.join(source, entry.name, "hook.ts"))
|
|
2418
2076
|
);
|
|
2419
2077
|
if (!hookDirs.length) {
|
|
2420
2078
|
return;
|
|
2421
2079
|
}
|
|
2422
2080
|
const config = {};
|
|
2423
2081
|
for (const entry of hookDirs) {
|
|
2424
|
-
const filePath =
|
|
2082
|
+
const filePath = path11.join(source, entry.name, "hook.ts");
|
|
2425
2083
|
mergeHooks(config, parseHookFile(await readFile6(filePath, "utf8"), entry.name));
|
|
2426
2084
|
}
|
|
2427
2085
|
await mkdir5(destination, { recursive: true });
|
|
2428
2086
|
await writeFile5(
|
|
2429
|
-
|
|
2087
|
+
path11.join(destination, "hooks.json"),
|
|
2430
2088
|
`${JSON.stringify(config, null, 2)}
|
|
2431
2089
|
`
|
|
2432
2090
|
);
|
|
@@ -2453,7 +2111,7 @@ function parseHookFile(source, fallbackName) {
|
|
|
2453
2111
|
throw new Error(`hooks/${fallbackName}/hook.ts must default-export hook({ ... }) or hooks({ ... }).`);
|
|
2454
2112
|
}
|
|
2455
2113
|
function parseHookDefinition(definition, fallbackName) {
|
|
2456
|
-
const event =
|
|
2114
|
+
const event = readStringProperty3(definition, "event");
|
|
2457
2115
|
if (!event) {
|
|
2458
2116
|
throw new Error(`hooks/${fallbackName}/hook.ts must declare an event string.`);
|
|
2459
2117
|
}
|
|
@@ -2463,7 +2121,7 @@ function parseHookDefinition(definition, fallbackName) {
|
|
|
2463
2121
|
}
|
|
2464
2122
|
return {
|
|
2465
2123
|
event,
|
|
2466
|
-
matcher:
|
|
2124
|
+
matcher: readStringProperty3(definition, "matcher"),
|
|
2467
2125
|
run: hooks
|
|
2468
2126
|
};
|
|
2469
2127
|
}
|
|
@@ -2483,7 +2141,7 @@ function parseHooksDefinition(definition, fallbackName) {
|
|
|
2483
2141
|
throw new Error(`hooks/${fallbackName}/hook.ts event "${event}" entries must be objects.`);
|
|
2484
2142
|
}
|
|
2485
2143
|
return stripUndefined2({
|
|
2486
|
-
matcher:
|
|
2144
|
+
matcher: readStringProperty3(entry, "matcher"),
|
|
2487
2145
|
hooks: readHookArray(entry, "run", fallbackName)
|
|
2488
2146
|
});
|
|
2489
2147
|
});
|
|
@@ -2506,7 +2164,7 @@ function parseHookHandlers(handlers, fallbackName) {
|
|
|
2506
2164
|
}
|
|
2507
2165
|
function parseHookHandler(handler, fallbackName) {
|
|
2508
2166
|
if (Node6.isObjectLiteralExpression(handler)) {
|
|
2509
|
-
const type =
|
|
2167
|
+
const type = readStringProperty3(handler, "type");
|
|
2510
2168
|
if (type !== "command" && type !== "http") {
|
|
2511
2169
|
throw new Error(`hooks/${fallbackName}/hook.ts hook handlers need type "command" or "http".`);
|
|
2512
2170
|
}
|
|
@@ -2556,7 +2214,7 @@ function objectLiteralToRecord(object) {
|
|
|
2556
2214
|
}
|
|
2557
2215
|
return stripUndefined2(record);
|
|
2558
2216
|
}
|
|
2559
|
-
function
|
|
2217
|
+
function readStringProperty3(object, propertyName) {
|
|
2560
2218
|
const property = object.getProperty(propertyName);
|
|
2561
2219
|
if (!property || !Node6.isPropertyAssignment(property)) {
|
|
2562
2220
|
return void 0;
|
|
@@ -2600,7 +2258,7 @@ function mergeHooks(target, source) {
|
|
|
2600
2258
|
|
|
2601
2259
|
// packages/compiler/src/plugin-components/passthrough.ts
|
|
2602
2260
|
import { cp as cp2, lstat as lstat2 } from "fs/promises";
|
|
2603
|
-
import
|
|
2261
|
+
import path12 from "path";
|
|
2604
2262
|
async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
2605
2263
|
for (const directory of [
|
|
2606
2264
|
"assets",
|
|
@@ -2609,18 +2267,18 @@ async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
|
2609
2267
|
"output-styles",
|
|
2610
2268
|
"themes"
|
|
2611
2269
|
]) {
|
|
2612
|
-
const source =
|
|
2270
|
+
const source = path12.join(rootDir, directory);
|
|
2613
2271
|
if (!existsSyncSafe(source)) {
|
|
2614
2272
|
continue;
|
|
2615
2273
|
}
|
|
2616
|
-
await cp2(source,
|
|
2274
|
+
await cp2(source, path12.join(pluginDir, directory), {
|
|
2617
2275
|
recursive: true,
|
|
2618
2276
|
filter: safePluginCopyFilter
|
|
2619
2277
|
});
|
|
2620
2278
|
}
|
|
2621
2279
|
}
|
|
2622
2280
|
async function safePluginCopyFilter(sourcePath) {
|
|
2623
|
-
const basename =
|
|
2281
|
+
const basename = path12.basename(sourcePath);
|
|
2624
2282
|
if (basename === "node_modules" || basename === ".git" || basename === ".env" || basename.startsWith(".env.")) {
|
|
2625
2283
|
return false;
|
|
2626
2284
|
}
|
|
@@ -2629,11 +2287,11 @@ async function safePluginCopyFilter(sourcePath) {
|
|
|
2629
2287
|
}
|
|
2630
2288
|
|
|
2631
2289
|
// packages/compiler/src/plugin-components/skills.ts
|
|
2632
|
-
import { existsSync as
|
|
2290
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2633
2291
|
import { cp as cp3, lstat as lstat3, mkdir as mkdir6, readdir as readdir5, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
2634
|
-
import
|
|
2292
|
+
import path13 from "path";
|
|
2635
2293
|
async function copySkills(rootDir, destination) {
|
|
2636
|
-
const source =
|
|
2294
|
+
const source = path13.join(rootDir, "skills");
|
|
2637
2295
|
if (!existsSyncSafe(source)) {
|
|
2638
2296
|
return;
|
|
2639
2297
|
}
|
|
@@ -2643,27 +2301,27 @@ async function copySkills(rootDir, destination) {
|
|
|
2643
2301
|
if (!entry.isDirectory()) {
|
|
2644
2302
|
continue;
|
|
2645
2303
|
}
|
|
2646
|
-
const sourceDir =
|
|
2647
|
-
const destinationDir =
|
|
2648
|
-
const staticSkill =
|
|
2649
|
-
const dynamicSkill =
|
|
2304
|
+
const sourceDir = path13.join(source, entry.name);
|
|
2305
|
+
const destinationDir = path13.join(destination, entry.name);
|
|
2306
|
+
const staticSkill = path13.join(sourceDir, "SKILL.md");
|
|
2307
|
+
const dynamicSkill = path13.join(sourceDir, "skill.ts");
|
|
2650
2308
|
await mkdir6(destinationDir, { recursive: true });
|
|
2651
|
-
if (
|
|
2309
|
+
if (existsSync4(staticSkill)) {
|
|
2652
2310
|
await cp3(sourceDir, destinationDir, {
|
|
2653
2311
|
recursive: true,
|
|
2654
|
-
filter: async (sourcePath) => !sourcePath.endsWith(`${
|
|
2312
|
+
filter: async (sourcePath) => !sourcePath.endsWith(`${path13.sep}skill.ts`) && await safeSkillCopyFilter(sourcePath)
|
|
2655
2313
|
});
|
|
2656
|
-
} else if (
|
|
2314
|
+
} else if (existsSync4(dynamicSkill)) {
|
|
2657
2315
|
const generated = parseDynamicSkill(
|
|
2658
2316
|
await readFile7(dynamicSkill, "utf8"),
|
|
2659
2317
|
entry.name
|
|
2660
2318
|
);
|
|
2661
|
-
await writeFile6(
|
|
2319
|
+
await writeFile6(path13.join(destinationDir, "SKILL.md"), generated);
|
|
2662
2320
|
}
|
|
2663
2321
|
}
|
|
2664
2322
|
}
|
|
2665
2323
|
async function safeSkillCopyFilter(sourcePath) {
|
|
2666
|
-
const basename =
|
|
2324
|
+
const basename = path13.basename(sourcePath);
|
|
2667
2325
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2668
2326
|
return false;
|
|
2669
2327
|
}
|
|
@@ -2689,25 +2347,25 @@ async function buildPluginPackages(rootDir, outRoot, manifest) {
|
|
|
2689
2347
|
await buildClaudePlugin(rootDir, outRoot, identity, manifest);
|
|
2690
2348
|
}
|
|
2691
2349
|
async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
2692
|
-
const pluginDir =
|
|
2693
|
-
await mkdir7(
|
|
2694
|
-
await copySkills(rootDir,
|
|
2695
|
-
await copyCommands(rootDir,
|
|
2696
|
-
await copyHooks(rootDir,
|
|
2697
|
-
await emitClaudeAgents(rootDir,
|
|
2350
|
+
const pluginDir = path14.join(outRoot, "claude-plugin");
|
|
2351
|
+
await mkdir7(path14.join(pluginDir, ".claude-plugin"), { recursive: true });
|
|
2352
|
+
await copySkills(rootDir, path14.join(pluginDir, "skills"));
|
|
2353
|
+
await copyCommands(rootDir, path14.join(pluginDir, "commands"));
|
|
2354
|
+
await copyHooks(rootDir, path14.join(pluginDir, "hooks"));
|
|
2355
|
+
await emitClaudeAgents(rootDir, path14.join(pluginDir, "agents"));
|
|
2698
2356
|
await copyClaudePassthroughDirectories(rootDir, pluginDir);
|
|
2699
|
-
await writeJson(
|
|
2357
|
+
await writeJson(path14.join(pluginDir, ".claude-plugin", "plugin.json"), {
|
|
2700
2358
|
name: identity.slug,
|
|
2701
2359
|
version: identity.version,
|
|
2702
2360
|
description: identity.description,
|
|
2703
2361
|
displayName: identity.name,
|
|
2704
2362
|
installationPreference: "available"
|
|
2705
2363
|
});
|
|
2706
|
-
await writeJson(
|
|
2364
|
+
await writeJson(path14.join(pluginDir, "version.json"), {
|
|
2707
2365
|
version: identity.version,
|
|
2708
2366
|
generatedBy: "sidecar"
|
|
2709
2367
|
});
|
|
2710
|
-
await writeJson(
|
|
2368
|
+
await writeJson(path14.join(pluginDir, ".mcp.json"), {
|
|
2711
2369
|
mcpServers: {
|
|
2712
2370
|
[identity.slug]: {
|
|
2713
2371
|
type: "http",
|
|
@@ -2715,7 +2373,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2715
2373
|
}
|
|
2716
2374
|
}
|
|
2717
2375
|
});
|
|
2718
|
-
await writeJson(
|
|
2376
|
+
await writeJson(path14.join(pluginDir, "settings.json"), {
|
|
2719
2377
|
sidecar: {
|
|
2720
2378
|
tools: manifest.tools.map((entry) => entry.id),
|
|
2721
2379
|
resources: manifest.resources.map((entry) => entry.uri),
|
|
@@ -2723,7 +2381,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2723
2381
|
}
|
|
2724
2382
|
});
|
|
2725
2383
|
await writeFile7(
|
|
2726
|
-
|
|
2384
|
+
path14.join(pluginDir, "README.md"),
|
|
2727
2385
|
`# ${identity.name} Claude Plugin
|
|
2728
2386
|
|
|
2729
2387
|
This package was generated by Sidecar.
|
|
@@ -2737,7 +2395,7 @@ Claude/Cowork plugin-specific components such as skills, slash commands, agents,
|
|
|
2737
2395
|
);
|
|
2738
2396
|
}
|
|
2739
2397
|
async function writeJson(filePath, value) {
|
|
2740
|
-
await mkdir7(
|
|
2398
|
+
await mkdir7(path14.dirname(filePath), { recursive: true });
|
|
2741
2399
|
await writeFile7(
|
|
2742
2400
|
filePath,
|
|
2743
2401
|
`${JSON.stringify(stripUndefined2(value), null, 2)}
|
|
@@ -2747,13 +2405,13 @@ async function writeJson(filePath, value) {
|
|
|
2747
2405
|
|
|
2748
2406
|
// packages/compiler/src/prompts.ts
|
|
2749
2407
|
import { readdir as readdir6 } from "fs/promises";
|
|
2750
|
-
import
|
|
2408
|
+
import path15 from "path";
|
|
2751
2409
|
import {
|
|
2752
2410
|
Node as Node7,
|
|
2753
2411
|
SyntaxKind as SyntaxKind5
|
|
2754
2412
|
} from "ts-morph";
|
|
2755
2413
|
async function analyzeProjectPrompts(rootDir) {
|
|
2756
|
-
const promptFiles = await findPromptFiles(
|
|
2414
|
+
const promptFiles = await findPromptFiles(path15.join(rootDir, "prompts"));
|
|
2757
2415
|
if (promptFiles.length === 0) {
|
|
2758
2416
|
return [];
|
|
2759
2417
|
}
|
|
@@ -2765,7 +2423,7 @@ async function analyzeProjectPrompts(rootDir) {
|
|
|
2765
2423
|
function analyzePromptFile(sourceFile, rootDir) {
|
|
2766
2424
|
const definition = findPromptDefinition(sourceFile);
|
|
2767
2425
|
const absoluteFile = sourceFile.getFilePath();
|
|
2768
|
-
const directory =
|
|
2426
|
+
const directory = path15.basename(path15.dirname(absoluteFile));
|
|
2769
2427
|
const name = getOptionalStringProperty2(definition, "name") ?? safePathSegment(directory);
|
|
2770
2428
|
const title = getRequiredStringProperty2(definition, "title", sourceFile);
|
|
2771
2429
|
const description = getOptionalStringProperty2(definition, "description");
|
|
@@ -2781,7 +2439,7 @@ function analyzePromptFile(sourceFile, rootDir) {
|
|
|
2781
2439
|
throw new CompilerError(sourceFile, "prompt({ ... }) must include a run method.");
|
|
2782
2440
|
}
|
|
2783
2441
|
return {
|
|
2784
|
-
sourceFile:
|
|
2442
|
+
sourceFile: path15.relative(rootDir, absoluteFile),
|
|
2785
2443
|
directory,
|
|
2786
2444
|
name,
|
|
2787
2445
|
title,
|
|
@@ -2800,7 +2458,7 @@ async function findPromptFiles(promptsDir) {
|
|
|
2800
2458
|
if (!entry.isDirectory()) {
|
|
2801
2459
|
continue;
|
|
2802
2460
|
}
|
|
2803
|
-
const filePath =
|
|
2461
|
+
const filePath = path15.join(promptsDir, entry.name, "prompt.ts");
|
|
2804
2462
|
if (existsSyncSafe(filePath)) {
|
|
2805
2463
|
files.push(filePath);
|
|
2806
2464
|
}
|
|
@@ -2922,7 +2580,7 @@ function readIcons(definition) {
|
|
|
2922
2580
|
return [{
|
|
2923
2581
|
src,
|
|
2924
2582
|
mimeType: getOptionalStringProperty2(object, "mimeType"),
|
|
2925
|
-
sizes:
|
|
2583
|
+
sizes: readStringArrayProperty3(object, "sizes")
|
|
2926
2584
|
}];
|
|
2927
2585
|
});
|
|
2928
2586
|
return icons.length ? icons : void 0;
|
|
@@ -2935,7 +2593,7 @@ function readObjectProperty4(definition, propertyName) {
|
|
|
2935
2593
|
const initializer = unwrapExpression(property.getInitializer());
|
|
2936
2594
|
return initializer && Node7.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
2937
2595
|
}
|
|
2938
|
-
function
|
|
2596
|
+
function readStringArrayProperty3(definition, propertyName) {
|
|
2939
2597
|
const property = definition.getProperty(propertyName);
|
|
2940
2598
|
if (!property || !Node7.isPropertyAssignment(property)) {
|
|
2941
2599
|
return void 0;
|
|
@@ -2949,13 +2607,13 @@ function readStringArrayProperty4(definition, propertyName) {
|
|
|
2949
2607
|
|
|
2950
2608
|
// packages/compiler/src/resources.ts
|
|
2951
2609
|
import { readdir as readdir7 } from "fs/promises";
|
|
2952
|
-
import
|
|
2610
|
+
import path16 from "path";
|
|
2953
2611
|
import {
|
|
2954
2612
|
Node as Node8,
|
|
2955
2613
|
SyntaxKind as SyntaxKind6
|
|
2956
2614
|
} from "ts-morph";
|
|
2957
2615
|
async function analyzeProjectResources(rootDir) {
|
|
2958
|
-
const resourceFiles = await findResourceFiles(
|
|
2616
|
+
const resourceFiles = await findResourceFiles(path16.join(rootDir, "resources"));
|
|
2959
2617
|
if (resourceFiles.length === 0) {
|
|
2960
2618
|
return [];
|
|
2961
2619
|
}
|
|
@@ -2967,7 +2625,7 @@ async function analyzeProjectResources(rootDir) {
|
|
|
2967
2625
|
function analyzeResourceFile(sourceFile, rootDir) {
|
|
2968
2626
|
const definition = findResourceDefinition(sourceFile);
|
|
2969
2627
|
const absoluteFile = sourceFile.getFilePath();
|
|
2970
|
-
const directory =
|
|
2628
|
+
const directory = path16.basename(path16.dirname(absoluteFile));
|
|
2971
2629
|
const defaultUri = `sidecar://resources/${safePathSegment(directory)}`;
|
|
2972
2630
|
const name = getRequiredStringProperty3(definition, "name", sourceFile);
|
|
2973
2631
|
const uri = getOptionalStringProperty3(definition, "uri") ?? defaultUri;
|
|
@@ -2985,7 +2643,7 @@ function analyzeResourceFile(sourceFile, rootDir) {
|
|
|
2985
2643
|
throw new CompilerError(sourceFile, "resource({ ... }) must include a read method.");
|
|
2986
2644
|
}
|
|
2987
2645
|
return {
|
|
2988
|
-
sourceFile:
|
|
2646
|
+
sourceFile: path16.relative(rootDir, absoluteFile),
|
|
2989
2647
|
directory,
|
|
2990
2648
|
uri,
|
|
2991
2649
|
name,
|
|
@@ -3008,7 +2666,7 @@ async function findResourceFiles(resourcesDir) {
|
|
|
3008
2666
|
if (!entry.isDirectory()) {
|
|
3009
2667
|
continue;
|
|
3010
2668
|
}
|
|
3011
|
-
const filePath =
|
|
2669
|
+
const filePath = path16.join(resourcesDir, entry.name, "resource.ts");
|
|
3012
2670
|
if (existsSyncSafe(filePath)) {
|
|
3013
2671
|
files.push(filePath);
|
|
3014
2672
|
}
|
|
@@ -3087,7 +2745,7 @@ function readAnnotations2(definition) {
|
|
|
3087
2745
|
return void 0;
|
|
3088
2746
|
}
|
|
3089
2747
|
const annotations = {};
|
|
3090
|
-
const audience =
|
|
2748
|
+
const audience = readStringArrayProperty4(initializer, "audience")?.filter((value) => value === "user" || value === "assistant");
|
|
3091
2749
|
const priority = getOptionalNumberProperty(initializer, "priority");
|
|
3092
2750
|
const lastModified = getOptionalStringProperty3(initializer, "lastModified");
|
|
3093
2751
|
if (audience?.length) annotations.audience = audience;
|
|
@@ -3116,7 +2774,7 @@ function readIcons2(definition) {
|
|
|
3116
2774
|
return [{
|
|
3117
2775
|
src,
|
|
3118
2776
|
mimeType: getOptionalStringProperty3(object, "mimeType"),
|
|
3119
|
-
sizes:
|
|
2777
|
+
sizes: readStringArrayProperty4(object, "sizes")
|
|
3120
2778
|
}];
|
|
3121
2779
|
});
|
|
3122
2780
|
return icons.length ? icons : void 0;
|
|
@@ -3129,7 +2787,7 @@ function readObjectProperty5(definition, propertyName) {
|
|
|
3129
2787
|
const initializer = unwrapExpression(property.getInitializer());
|
|
3130
2788
|
return initializer && Node8.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
3131
2789
|
}
|
|
3132
|
-
function
|
|
2790
|
+
function readStringArrayProperty4(definition, propertyName) {
|
|
3133
2791
|
const property = definition.getProperty(propertyName);
|
|
3134
2792
|
if (!property || !Node8.isPropertyAssignment(property)) {
|
|
3135
2793
|
return void 0;
|
|
@@ -3142,21 +2800,19 @@ function readStringArrayProperty5(definition, propertyName) {
|
|
|
3142
2800
|
}
|
|
3143
2801
|
|
|
3144
2802
|
// packages/compiler/src/server-output.ts
|
|
3145
|
-
import { existsSync as
|
|
2803
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3146
2804
|
import { mkdir as mkdir8, rm, writeFile as writeFile8 } from "fs/promises";
|
|
3147
|
-
import
|
|
2805
|
+
import path17 from "path";
|
|
3148
2806
|
import { build as esbuild2 } from "esbuild";
|
|
3149
2807
|
var SERVER_ENTRYPOINT = "server/index.js";
|
|
3150
|
-
var
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
async function buildServerOutput(rootDir, outDir, manifest, identity, host = "node", options = {}) {
|
|
3154
|
-
const cacheDir = path18.join(rootDir, ".sidecar", "cache", "server");
|
|
2808
|
+
var VERCEL_ENTRYPOINT = "api/sidecar.js";
|
|
2809
|
+
async function buildServerOutput(rootDir, outDir, manifest, identity, host = "node") {
|
|
2810
|
+
const cacheDir = path17.join(rootDir, ".sidecar", "cache", "server");
|
|
3155
2811
|
await mkdir8(cacheDir, { recursive: true });
|
|
3156
|
-
const entryFile =
|
|
2812
|
+
const entryFile = path17.join(cacheDir, "index.ts");
|
|
3157
2813
|
await writeFile8(entryFile, renderServerEntry(rootDir, entryFile, manifest, identity));
|
|
3158
|
-
const serverFile =
|
|
3159
|
-
await mkdir8(
|
|
2814
|
+
const serverFile = path17.join(outDir, SERVER_ENTRYPOINT);
|
|
2815
|
+
await mkdir8(path17.dirname(serverFile), { recursive: true });
|
|
3160
2816
|
await esbuild2({
|
|
3161
2817
|
absWorkingDir: rootDir,
|
|
3162
2818
|
alias: sidecarBundleAliases(rootDir),
|
|
@@ -3170,30 +2826,26 @@ const require = __sidecarCreateRequire(import.meta.url);`
|
|
|
3170
2826
|
legalComments: "none",
|
|
3171
2827
|
minify: false,
|
|
3172
2828
|
nodePaths: [
|
|
3173
|
-
|
|
3174
|
-
|
|
2829
|
+
path17.join(rootDir, "node_modules"),
|
|
2830
|
+
path17.join(process.cwd(), "node_modules")
|
|
3175
2831
|
],
|
|
3176
2832
|
outfile: serverFile,
|
|
3177
2833
|
platform: "node",
|
|
3178
2834
|
sourcemap: false,
|
|
3179
2835
|
target: "node20"
|
|
3180
2836
|
});
|
|
3181
|
-
await writeFile8(
|
|
2837
|
+
await writeFile8(path17.join(outDir, "package.json"), renderServerPackage(identity));
|
|
3182
2838
|
if (host === "vercel") {
|
|
3183
|
-
|
|
3184
|
-
await
|
|
3185
|
-
await
|
|
3186
|
-
await writeFile8(path18.join(outDir, VERCEL_HANDLER_FILE), renderVercelEntrypoint());
|
|
3187
|
-
await writeFile8(path18.join(outDir, ".vc-config.json"), renderVercelFunctionConfig());
|
|
3188
|
-
await mkdir8(vercelOutputDir, { recursive: true });
|
|
3189
|
-
await writeFile8(path18.join(vercelOutputDir, "config.json"), renderVercelOutputConfig());
|
|
2839
|
+
await mkdir8(path17.join(outDir, "api"), { recursive: true });
|
|
2840
|
+
await writeFile8(path17.join(outDir, VERCEL_ENTRYPOINT), renderVercelEntrypoint());
|
|
2841
|
+
await writeFile8(path17.join(outDir, "vercel.json"), renderVercelConfig());
|
|
3190
2842
|
} else {
|
|
3191
|
-
await rm(
|
|
3192
|
-
await rm(
|
|
2843
|
+
await rm(path17.join(outDir, "api"), { recursive: true, force: true });
|
|
2844
|
+
await rm(path17.join(outDir, "vercel.json"), { force: true });
|
|
3193
2845
|
}
|
|
3194
2846
|
}
|
|
3195
2847
|
function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
3196
|
-
const entryDir =
|
|
2848
|
+
const entryDir = path17.dirname(entryFile);
|
|
3197
2849
|
const tools = manifest.tools;
|
|
3198
2850
|
const resources = manifest.resources;
|
|
3199
2851
|
const prompts = manifest.prompts;
|
|
@@ -3206,17 +2858,17 @@ function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
|
3206
2858
|
`import { isSidecarPrompt, isSidecarResource, isSidecarTool } from "@sidecar-ai/core";`,
|
|
3207
2859
|
`import { isSidecarProxy } from "@sidecar-ai/server/proxy";`,
|
|
3208
2860
|
...tools.map(
|
|
3209
|
-
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
2861
|
+
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3210
2862
|
),
|
|
3211
2863
|
...resources.map(
|
|
3212
|
-
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
2864
|
+
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3213
2865
|
),
|
|
3214
2866
|
...prompts.map(
|
|
3215
|
-
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
2867
|
+
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, entry.sourceFile)))};`
|
|
3216
2868
|
),
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
2869
|
+
existsSync5(path17.join(rootDir, "auth.ts")) ? `import authExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "auth.ts")))};` : `const authExport = undefined;`,
|
|
2870
|
+
existsSync5(path17.join(rootDir, "proxy.ts")) ? `import proxyExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "proxy.ts")))};` : `const proxyExport = undefined;`,
|
|
2871
|
+
existsSync5(path17.join(rootDir, "sidecar.config.ts")) ? `import configExport from ${JSON.stringify(toImportSpecifier(entryDir, path17.join(rootDir, "sidecar.config.ts")))};` : `const configExport = undefined;`
|
|
3220
2872
|
].join("\n");
|
|
3221
2873
|
return `${imports}
|
|
3222
2874
|
|
|
@@ -3327,7 +2979,7 @@ function unwrapRuntimeDefault(value) {
|
|
|
3327
2979
|
value &&
|
|
3328
2980
|
typeof value === "object" &&
|
|
3329
2981
|
"default" in value &&
|
|
3330
|
-
Object.keys(value).
|
|
2982
|
+
Object.keys(value).length === 1
|
|
3331
2983
|
) {
|
|
3332
2984
|
return unwrapRuntimeDefault(value.default);
|
|
3333
2985
|
}
|
|
@@ -3387,29 +3039,23 @@ function renderServerPackage(identity) {
|
|
|
3387
3039
|
`;
|
|
3388
3040
|
}
|
|
3389
3041
|
function renderVercelEntrypoint() {
|
|
3390
|
-
return `export { default } from "
|
|
3391
|
-
`;
|
|
3392
|
-
}
|
|
3393
|
-
function renderVercelFunctionConfig() {
|
|
3394
|
-
return `${JSON.stringify({
|
|
3395
|
-
runtime: "nodejs22.x",
|
|
3396
|
-
handler: VERCEL_HANDLER_FILE,
|
|
3397
|
-
launcherType: "Nodejs",
|
|
3398
|
-
shouldAddHelpers: true,
|
|
3399
|
-
supportsResponseStreaming: true,
|
|
3400
|
-
maxDuration: 300
|
|
3401
|
-
}, null, 2)}
|
|
3042
|
+
return `export { default } from "../server/index.js";
|
|
3402
3043
|
`;
|
|
3403
3044
|
}
|
|
3404
|
-
function
|
|
3045
|
+
function renderVercelConfig() {
|
|
3405
3046
|
return `${JSON.stringify({
|
|
3406
|
-
|
|
3407
|
-
routes: [
|
|
3047
|
+
rewrites: [
|
|
3408
3048
|
{
|
|
3409
|
-
|
|
3410
|
-
|
|
3049
|
+
source: "/(.*)",
|
|
3050
|
+
destination: "/api/sidecar"
|
|
3051
|
+
}
|
|
3052
|
+
],
|
|
3053
|
+
functions: {
|
|
3054
|
+
"api/sidecar.js": {
|
|
3055
|
+
includeFiles: "public/**",
|
|
3056
|
+
maxDuration: 300
|
|
3411
3057
|
}
|
|
3412
|
-
|
|
3058
|
+
}
|
|
3413
3059
|
}, null, 2)}
|
|
3414
3060
|
`;
|
|
3415
3061
|
}
|
|
@@ -3419,35 +3065,35 @@ function sidecarBundleAliases(rootDir) {
|
|
|
3419
3065
|
return void 0;
|
|
3420
3066
|
}
|
|
3421
3067
|
return {
|
|
3422
|
-
"sidecar-ai":
|
|
3423
|
-
"@sidecar-ai/auth":
|
|
3424
|
-
"@sidecar-ai/core":
|
|
3425
|
-
"@sidecar-ai/server":
|
|
3426
|
-
"@sidecar-ai/server/proxy":
|
|
3427
|
-
"@sidecar-ai/client":
|
|
3428
|
-
"@sidecar-ai/react":
|
|
3429
|
-
"@sidecar-ai/native":
|
|
3430
|
-
"@sidecar-ai/native/components":
|
|
3431
|
-
"@sidecar-ai/openai":
|
|
3432
|
-
"@sidecar-ai/openai/components":
|
|
3433
|
-
"@sidecar-ai/openai/official":
|
|
3434
|
-
"@sidecar-ai/anthropic":
|
|
3435
|
-
"@sidecar-ai/anthropic/agent":
|
|
3436
|
-
"@sidecar-ai/anthropic/command":
|
|
3437
|
-
"@sidecar-ai/anthropic/components":
|
|
3438
|
-
"@sidecar-ai/anthropic/hooks":
|
|
3439
|
-
"@sidecar-ai/anthropic/mcp":
|
|
3440
|
-
"@sidecar-ai/anthropic/plugin":
|
|
3441
|
-
"@sidecar-ai/anthropic/skill":
|
|
3068
|
+
"sidecar-ai": path17.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
3069
|
+
"@sidecar-ai/auth": path17.join(repoRoot, "packages", "auth", "src", "index.ts"),
|
|
3070
|
+
"@sidecar-ai/core": path17.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
3071
|
+
"@sidecar-ai/server": path17.join(repoRoot, "packages", "server", "src", "index.ts"),
|
|
3072
|
+
"@sidecar-ai/server/proxy": path17.join(repoRoot, "packages", "server", "src", "proxy.ts"),
|
|
3073
|
+
"@sidecar-ai/client": path17.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
3074
|
+
"@sidecar-ai/react": path17.join(repoRoot, "packages", "react", "src", "index.ts"),
|
|
3075
|
+
"@sidecar-ai/native": path17.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
3076
|
+
"@sidecar-ai/native/components": path17.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
3077
|
+
"@sidecar-ai/openai": path17.join(repoRoot, "packages", "openai", "src", "index.ts"),
|
|
3078
|
+
"@sidecar-ai/openai/components": path17.join(repoRoot, "packages", "openai", "src", "components.tsx"),
|
|
3079
|
+
"@sidecar-ai/openai/official": path17.join(repoRoot, "packages", "openai", "src", "official.ts"),
|
|
3080
|
+
"@sidecar-ai/anthropic": path17.join(repoRoot, "packages", "anthropic", "src", "index.ts"),
|
|
3081
|
+
"@sidecar-ai/anthropic/agent": path17.join(repoRoot, "packages", "anthropic", "src", "agent.ts"),
|
|
3082
|
+
"@sidecar-ai/anthropic/command": path17.join(repoRoot, "packages", "anthropic", "src", "command.ts"),
|
|
3083
|
+
"@sidecar-ai/anthropic/components": path17.join(repoRoot, "packages", "anthropic", "src", "components.tsx"),
|
|
3084
|
+
"@sidecar-ai/anthropic/hooks": path17.join(repoRoot, "packages", "anthropic", "src", "hooks.ts"),
|
|
3085
|
+
"@sidecar-ai/anthropic/mcp": path17.join(repoRoot, "packages", "anthropic", "src", "mcp.ts"),
|
|
3086
|
+
"@sidecar-ai/anthropic/plugin": path17.join(repoRoot, "packages", "anthropic", "src", "plugin.ts"),
|
|
3087
|
+
"@sidecar-ai/anthropic/skill": path17.join(repoRoot, "packages", "anthropic", "src", "skill.ts")
|
|
3442
3088
|
};
|
|
3443
3089
|
}
|
|
3444
3090
|
function findSidecarRepoRoot2(startDir) {
|
|
3445
|
-
let current =
|
|
3091
|
+
let current = path17.resolve(startDir);
|
|
3446
3092
|
while (true) {
|
|
3447
|
-
if (
|
|
3093
|
+
if (existsSync5(path17.join(current, "packages", "core", "src", "index.ts"))) {
|
|
3448
3094
|
return current;
|
|
3449
3095
|
}
|
|
3450
|
-
const parent =
|
|
3096
|
+
const parent = path17.dirname(current);
|
|
3451
3097
|
if (parent === current) {
|
|
3452
3098
|
return void 0;
|
|
3453
3099
|
}
|
|
@@ -3457,11 +3103,10 @@ function findSidecarRepoRoot2(startDir) {
|
|
|
3457
3103
|
|
|
3458
3104
|
// packages/compiler/src/build.ts
|
|
3459
3105
|
async function buildProject(options) {
|
|
3460
|
-
const rootDir =
|
|
3106
|
+
const rootDir = path18.resolve(options.rootDir);
|
|
3107
|
+
const target = options.target ?? "mcp";
|
|
3108
|
+
const host = options.host ?? "node";
|
|
3461
3109
|
const config = analyzeProjectConfig(rootDir);
|
|
3462
|
-
const target = options.target ?? config.build.target ?? "mcp";
|
|
3463
|
-
const host = options.host ?? config.build.host ?? "node";
|
|
3464
|
-
const plugins = options.plugins ?? config.build.plugins ?? false;
|
|
3465
3110
|
const tools = await analyzeProjectTools(rootDir, { target });
|
|
3466
3111
|
const resources = await analyzeProjectResources(rootDir);
|
|
3467
3112
|
const resourceTemplates = [];
|
|
@@ -3477,9 +3122,8 @@ async function buildProject(options) {
|
|
|
3477
3122
|
if (errors.length) {
|
|
3478
3123
|
throw new Error(errors.map(formatDiagnostic).join("\n"));
|
|
3479
3124
|
}
|
|
3480
|
-
const outDir = resolveInsideRoot(rootDir, options.outDir ??
|
|
3481
|
-
|
|
3482
|
-
await buildWidgets(rootDir, runtimeOutDir, tools, config.build.widgets);
|
|
3125
|
+
const outDir = resolveInsideRoot(rootDir, options.outDir ?? "out/mcp");
|
|
3126
|
+
await buildWidgets(rootDir, outDir, tools);
|
|
3483
3127
|
const manifest = {
|
|
3484
3128
|
version: 1,
|
|
3485
3129
|
target,
|
|
@@ -3493,47 +3137,24 @@ async function buildProject(options) {
|
|
|
3493
3137
|
prompts,
|
|
3494
3138
|
diagnostics
|
|
3495
3139
|
};
|
|
3496
|
-
await mkdir9(
|
|
3140
|
+
await mkdir9(outDir, { recursive: true });
|
|
3497
3141
|
await writeFile9(
|
|
3498
|
-
|
|
3142
|
+
path18.join(outDir, "manifest.sidecar.json"),
|
|
3499
3143
|
`${JSON.stringify(manifest, null, 2)}
|
|
3500
3144
|
`
|
|
3501
3145
|
);
|
|
3502
|
-
await writeFile9(
|
|
3146
|
+
await writeFile9(path18.join(outDir, "README.md"), renderMcpReadme(manifest));
|
|
3503
3147
|
await writeGeneratedTypes(rootDir, tools);
|
|
3504
|
-
await buildServerOutput(rootDir,
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
if (plugins) {
|
|
3508
|
-
await buildPluginPackages(rootDir, resolvePluginOutputBase(rootDir, outDir, host), manifest);
|
|
3148
|
+
await buildServerOutput(rootDir, outDir, manifest, identity, host);
|
|
3149
|
+
if (options.plugins) {
|
|
3150
|
+
await buildPluginPackages(rootDir, path18.dirname(outDir), manifest);
|
|
3509
3151
|
}
|
|
3510
3152
|
return manifest;
|
|
3511
3153
|
}
|
|
3512
|
-
function defaultBuildOutDir(host, target) {
|
|
3513
|
-
if (host === "vercel") {
|
|
3514
|
-
return ".vercel/output";
|
|
3515
|
-
}
|
|
3516
|
-
return `out/${target}`;
|
|
3517
|
-
}
|
|
3518
|
-
function resolveRuntimeOutputDir(outDir, host) {
|
|
3519
|
-
if (host === "vercel") {
|
|
3520
|
-
return path19.join(outDir, VERCEL_FUNCTION_DIR);
|
|
3521
|
-
}
|
|
3522
|
-
return outDir;
|
|
3523
|
-
}
|
|
3524
|
-
function resolvePluginOutputBase(rootDir, outDir, host) {
|
|
3525
|
-
if (host === "vercel" && isVercelBuildOutputDir(outDir)) {
|
|
3526
|
-
return path19.join(rootDir, "out");
|
|
3527
|
-
}
|
|
3528
|
-
return path19.dirname(outDir);
|
|
3529
|
-
}
|
|
3530
|
-
function isVercelBuildOutputDir(outDir) {
|
|
3531
|
-
return path19.basename(outDir) === "output" && path19.basename(path19.dirname(outDir)) === ".vercel";
|
|
3532
|
-
}
|
|
3533
3154
|
function resolveInsideRoot(rootDir, output) {
|
|
3534
|
-
const resolved =
|
|
3535
|
-
const relative =
|
|
3536
|
-
if (relative.startsWith("..") ||
|
|
3155
|
+
const resolved = path18.resolve(rootDir, output);
|
|
3156
|
+
const relative = path18.relative(rootDir, resolved);
|
|
3157
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative)) {
|
|
3537
3158
|
throw new Error(`Build output must stay inside the project root: ${output}`);
|
|
3538
3159
|
}
|
|
3539
3160
|
return resolved;
|
|
@@ -3586,7 +3207,7 @@ Set \`PORT\` or \`SIDECAR_PORT\` to choose the listen port. Hosted/authenticated
|
|
|
3586
3207
|
function renderVercelReadmeSection() {
|
|
3587
3208
|
return `## Deploy To Vercel
|
|
3588
3209
|
|
|
3589
|
-
This output
|
|
3210
|
+
This output includes a Vercel Function shim at \`api/sidecar.js\` and a \`vercel.json\` rewrite that sends Streamable HTTP traffic to \`/mcp\`. Deploy this output directory with Vercel and set \`SIDECAR_MCP_URL\` to the public \`https://.../mcp\` URL.
|
|
3590
3211
|
`;
|
|
3591
3212
|
}
|
|
3592
3213
|
export {
|