@sidecar-ai/compiler 0.1.0-alpha.6 → 0.1.0-alpha.7
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 -1
- package/dist/index.js +571 -285
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// packages/core/src/index.ts
|
|
2
|
+
var toolBrand = /* @__PURE__ */ Symbol.for("sidecar.tool");
|
|
2
3
|
var toolResultBrand = /* @__PURE__ */ Symbol.for("sidecar.toolResult");
|
|
3
4
|
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
|
+
}
|
|
4
10
|
var toolResult = Object.assign(
|
|
5
11
|
createToolResult,
|
|
6
12
|
{
|
|
@@ -27,9 +33,9 @@ var resourceResult = Object.assign(
|
|
|
27
33
|
);
|
|
28
34
|
function createToolResult(input) {
|
|
29
35
|
const resultEnvelope = stripUndefined({
|
|
30
|
-
structuredContent: input.structuredContent,
|
|
36
|
+
structuredContent: stripJsonUndefined(input.structuredContent),
|
|
31
37
|
content: normalizeRequiredContent(input.content),
|
|
32
|
-
_meta: input.meta,
|
|
38
|
+
_meta: stripJsonUndefined(input.meta),
|
|
33
39
|
isError: input.isError
|
|
34
40
|
});
|
|
35
41
|
Object.defineProperty(resultEnvelope, toolResultBrand, {
|
|
@@ -271,10 +277,24 @@ function isReadonlyArray(value) {
|
|
|
271
277
|
function stripUndefined(value) {
|
|
272
278
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
273
279
|
}
|
|
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
|
+
}
|
|
274
294
|
|
|
275
295
|
// packages/compiler/src/analyze.ts
|
|
276
296
|
import { readdir } from "fs/promises";
|
|
277
|
-
import
|
|
297
|
+
import path5 from "path";
|
|
278
298
|
import {
|
|
279
299
|
Node as Node4,
|
|
280
300
|
SyntaxKind as SyntaxKind2
|
|
@@ -441,14 +461,7 @@ function devSidecarTypePaths() {
|
|
|
441
461
|
import {
|
|
442
462
|
Node as Node2
|
|
443
463
|
} from "ts-morph";
|
|
444
|
-
function getParamsSchema(
|
|
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
|
-
}
|
|
464
|
+
function getParamsSchema(_definition, execute) {
|
|
452
465
|
const [params] = execute.getParameters();
|
|
453
466
|
if (!params) {
|
|
454
467
|
return emptyObjectSchema();
|
|
@@ -469,74 +482,6 @@ function getOutputSchema(definition, execute) {
|
|
|
469
482
|
}
|
|
470
483
|
return typeToJsonSchema(returnType);
|
|
471
484
|
}
|
|
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
|
-
}
|
|
540
485
|
function typeToJsonSchema(type, description) {
|
|
541
486
|
const withoutUndefined = removeUndefined(type);
|
|
542
487
|
const schema = typeToJsonSchemaInner(withoutUndefined);
|
|
@@ -682,11 +627,102 @@ function schemaDescription(symbol) {
|
|
|
682
627
|
}).find((comment) => comment.trim().length > 0);
|
|
683
628
|
}
|
|
684
629
|
|
|
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
|
+
|
|
685
720
|
// packages/compiler/src/widgets.ts
|
|
686
721
|
import { createHash } from "crypto";
|
|
687
|
-
import { existsSync as
|
|
722
|
+
import { existsSync as existsSync3 } from "fs";
|
|
688
723
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
689
|
-
import
|
|
724
|
+
import path4 from "path";
|
|
725
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
690
726
|
import { build as esbuild } from "esbuild";
|
|
691
727
|
import postcss from "postcss";
|
|
692
728
|
import {
|
|
@@ -694,28 +730,29 @@ import {
|
|
|
694
730
|
SyntaxKind
|
|
695
731
|
} from "ts-morph";
|
|
696
732
|
var CLAUDE_FONT_RESOURCE_DOMAIN = "https://assets.claude.ai";
|
|
697
|
-
async function buildWidgets(rootDir, outDir, tools) {
|
|
733
|
+
async function buildWidgets(rootDir, outDir, tools, config = void 0) {
|
|
698
734
|
const widgets = tools.filter(
|
|
699
735
|
(entry) => Boolean(entry.widget)
|
|
700
736
|
);
|
|
701
737
|
if (!widgets.length) {
|
|
702
738
|
return;
|
|
703
739
|
}
|
|
704
|
-
const cacheDir =
|
|
740
|
+
const cacheDir = path4.join(rootDir, ".sidecar", "cache", "widgets");
|
|
705
741
|
await mkdir(cacheDir, { recursive: true });
|
|
706
742
|
const appStyle = await prepareAppStyle(rootDir, cacheDir);
|
|
743
|
+
const configure = await loadWidgetBundlerHook(rootDir, cacheDir, config?.configure);
|
|
707
744
|
for (const entry of widgets) {
|
|
708
|
-
const sourceFile =
|
|
745
|
+
const sourceFile = path4.join(rootDir, entry.widget.sourceFile);
|
|
709
746
|
const safeId = safePathSegment(entry.id);
|
|
710
|
-
const entryFile =
|
|
711
|
-
const importPath = toImportSpecifier(
|
|
747
|
+
const entryFile = path4.join(cacheDir, `${safeId}.entry.tsx`);
|
|
748
|
+
const importPath = toImportSpecifier(path4.dirname(entryFile), sourceFile);
|
|
712
749
|
await writeFile(
|
|
713
750
|
entryFile,
|
|
714
751
|
`import React from "react";
|
|
715
752
|
import { createRoot } from "react-dom/client";
|
|
716
753
|
import { SidecarWidgetRoot } from "@sidecar-ai/react";
|
|
717
754
|
import "@sidecar-ai/native/styles.css";
|
|
718
|
-
${appStyle ? `import ${JSON.stringify(toImportSpecifier(
|
|
755
|
+
${appStyle ? `import ${JSON.stringify(toImportSpecifier(path4.dirname(entryFile), appStyle))};` : ""}
|
|
719
756
|
import Component from ${JSON.stringify(importPath)};
|
|
720
757
|
|
|
721
758
|
createRoot(document.getElementById("root")!).render(
|
|
@@ -723,7 +760,7 @@ createRoot(document.getElementById("root")!).render(
|
|
|
723
760
|
);
|
|
724
761
|
`
|
|
725
762
|
);
|
|
726
|
-
const
|
|
763
|
+
const baseOptions = enforceWidgetBuildInvariants({
|
|
727
764
|
absWorkingDir: rootDir,
|
|
728
765
|
alias: devSidecarBundleAliases(rootDir),
|
|
729
766
|
bundle: true,
|
|
@@ -732,55 +769,184 @@ createRoot(document.getElementById("root")!).render(
|
|
|
732
769
|
jsx: "automatic",
|
|
733
770
|
minify: false,
|
|
734
771
|
nodePaths: [
|
|
735
|
-
|
|
736
|
-
|
|
772
|
+
path4.join(rootDir, "node_modules"),
|
|
773
|
+
path4.join(process.cwd(), "node_modules")
|
|
737
774
|
],
|
|
738
775
|
outfile: "widget.js",
|
|
739
776
|
platform: "browser",
|
|
740
777
|
sourcemap: false,
|
|
741
778
|
write: false
|
|
742
779
|
});
|
|
743
|
-
const
|
|
744
|
-
const
|
|
780
|
+
const staticOptions = widgetBuildOptionsFromConfig(rootDir, config);
|
|
781
|
+
const configuredOptions = configure ? await configureWidgetBuild(configure, {
|
|
782
|
+
rootDir,
|
|
783
|
+
outDir,
|
|
784
|
+
entryFile,
|
|
785
|
+
widget: {
|
|
786
|
+
toolId: entry.id,
|
|
787
|
+
toolName: entry.name,
|
|
788
|
+
target: entry.target,
|
|
789
|
+
sourceFile: entry.widget.sourceFile
|
|
790
|
+
},
|
|
791
|
+
esbuildOptions: mergeWidgetBuildOptions(baseOptions, staticOptions)
|
|
792
|
+
}) : void 0;
|
|
793
|
+
const bundled = await esbuild(enforceWidgetBuildInvariants(
|
|
794
|
+
mergeWidgetBuildOptions(baseOptions, staticOptions, configuredOptions),
|
|
795
|
+
{ rootDir, entryFile }
|
|
796
|
+
));
|
|
797
|
+
const outputFiles = bundled.outputFiles ?? [];
|
|
798
|
+
const javascript = outputFiles.find((file) => file.path.endsWith(".js"))?.text ?? "";
|
|
799
|
+
const css = outputFiles.filter((file) => file.path.endsWith(".css")).map((file) => file.text).join("\n");
|
|
745
800
|
const html = renderWidgetHtml(entry.name, javascript, css);
|
|
746
801
|
const hash = createHash("sha256").update(html).digest("hex").slice(0, 12);
|
|
747
|
-
const outputDir =
|
|
748
|
-
const outputFile =
|
|
802
|
+
const outputDir = path4.join(outDir, "public", "widgets", safeId);
|
|
803
|
+
const outputFile = path4.join(outputDir, `widget.${hash}.html`);
|
|
749
804
|
const resourceUri = `ui://${safeId}/widget.${hash}.html`;
|
|
750
805
|
await mkdir(outputDir, { recursive: true });
|
|
751
806
|
await writeFile(outputFile, html);
|
|
752
807
|
entry.widget.resourceUri = resourceUri;
|
|
753
808
|
entry.widget.resourceMeta = widgetResourceMeta(entry.widget.options, entry.target);
|
|
754
|
-
entry.widget.outputFile =
|
|
809
|
+
entry.widget.outputFile = path4.relative(outDir, outputFile);
|
|
755
810
|
entry.descriptor._meta = mergeWidgetMeta(entry.descriptor._meta, widgetMeta(resourceUri, entry.widget.options, entry.target));
|
|
756
811
|
}
|
|
757
812
|
}
|
|
813
|
+
function widgetBuildOptionsFromConfig(rootDir, config) {
|
|
814
|
+
const esbuildConfig = config?.esbuild;
|
|
815
|
+
if (!esbuildConfig) {
|
|
816
|
+
return void 0;
|
|
817
|
+
}
|
|
818
|
+
return {
|
|
819
|
+
alias: normalizeAliases(rootDir, esbuildConfig.alias),
|
|
820
|
+
conditions: esbuildConfig.conditions,
|
|
821
|
+
define: esbuildConfig.define,
|
|
822
|
+
external: esbuildConfig.external,
|
|
823
|
+
jsx: esbuildConfig.jsx,
|
|
824
|
+
jsxImportSource: esbuildConfig.jsxImportSource,
|
|
825
|
+
loader: esbuildConfig.loader,
|
|
826
|
+
mainFields: esbuildConfig.mainFields
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
async function loadWidgetBundlerHook(rootDir, cacheDir, hookPath) {
|
|
830
|
+
if (!hookPath) {
|
|
831
|
+
return void 0;
|
|
832
|
+
}
|
|
833
|
+
const sourcePath = path4.resolve(rootDir, hookPath);
|
|
834
|
+
const relative = path4.relative(rootDir, sourcePath);
|
|
835
|
+
if (relative.startsWith("..") || path4.isAbsolute(relative)) {
|
|
836
|
+
throw new Error(`Widget bundler hook must stay inside the project root: ${hookPath}`);
|
|
837
|
+
}
|
|
838
|
+
if (!existsSync3(sourcePath)) {
|
|
839
|
+
throw new Error(`Widget bundler hook not found: ${hookPath}`);
|
|
840
|
+
}
|
|
841
|
+
const outputFile = path4.join(cacheDir, `widget-bundler.${contentHash(hookPath)}.mjs`);
|
|
842
|
+
await esbuild({
|
|
843
|
+
absWorkingDir: rootDir,
|
|
844
|
+
alias: devSidecarBundleAliases(rootDir),
|
|
845
|
+
bundle: true,
|
|
846
|
+
entryPoints: [sourcePath],
|
|
847
|
+
format: "esm",
|
|
848
|
+
nodePaths: [
|
|
849
|
+
path4.join(rootDir, "node_modules"),
|
|
850
|
+
path4.join(process.cwd(), "node_modules")
|
|
851
|
+
],
|
|
852
|
+
outfile: outputFile,
|
|
853
|
+
packages: "external",
|
|
854
|
+
platform: "node",
|
|
855
|
+
target: "node20"
|
|
856
|
+
});
|
|
857
|
+
const module = await import(`${pathToFileURL2(outputFile).href}?t=${Date.now()}`);
|
|
858
|
+
if (typeof module.default !== "function") {
|
|
859
|
+
throw new Error(`Widget bundler hook must default-export a function: ${hookPath}`);
|
|
860
|
+
}
|
|
861
|
+
return module.default;
|
|
862
|
+
}
|
|
863
|
+
async function configureWidgetBuild(hook, input) {
|
|
864
|
+
const result = await hook(input);
|
|
865
|
+
if (!result) {
|
|
866
|
+
return void 0;
|
|
867
|
+
}
|
|
868
|
+
if (typeof result === "object" && "esbuildOptions" in result) {
|
|
869
|
+
return result.esbuildOptions;
|
|
870
|
+
}
|
|
871
|
+
return result;
|
|
872
|
+
}
|
|
873
|
+
function mergeWidgetBuildOptions(...options) {
|
|
874
|
+
const merged = {};
|
|
875
|
+
for (const option of options) {
|
|
876
|
+
if (!option) {
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
const previousAlias = merged.alias;
|
|
880
|
+
const previousDefine = merged.define;
|
|
881
|
+
const previousLoader = merged.loader;
|
|
882
|
+
const previousExternal = merged.external;
|
|
883
|
+
const previousNodePaths = merged.nodePaths;
|
|
884
|
+
const previousPlugins = merged.plugins;
|
|
885
|
+
Object.assign(merged, option);
|
|
886
|
+
merged.alias = { ...previousAlias ?? {}, ...option.alias ?? {} };
|
|
887
|
+
merged.define = { ...previousDefine ?? {}, ...option.define ?? {} };
|
|
888
|
+
merged.loader = { ...previousLoader ?? {}, ...option.loader ?? {} };
|
|
889
|
+
merged.external = uniqueStrings([...previousExternal ?? [], ...option.external ?? []]);
|
|
890
|
+
merged.nodePaths = uniqueStrings([...previousNodePaths ?? [], ...option.nodePaths ?? []]);
|
|
891
|
+
merged.plugins = [...previousPlugins ?? [], ...option.plugins ?? []];
|
|
892
|
+
}
|
|
893
|
+
return merged;
|
|
894
|
+
}
|
|
895
|
+
function enforceWidgetBuildInvariants(options, required) {
|
|
896
|
+
return {
|
|
897
|
+
...options,
|
|
898
|
+
absWorkingDir: required?.rootDir ?? options.absWorkingDir,
|
|
899
|
+
bundle: true,
|
|
900
|
+
entryPoints: required ? [required.entryFile] : options.entryPoints,
|
|
901
|
+
format: "iife",
|
|
902
|
+
outfile: "widget.js",
|
|
903
|
+
platform: "browser",
|
|
904
|
+
write: false
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
function normalizeAliases(rootDir, aliases) {
|
|
908
|
+
if (!aliases) {
|
|
909
|
+
return void 0;
|
|
910
|
+
}
|
|
911
|
+
return Object.fromEntries(
|
|
912
|
+
Object.entries(aliases).map(([key, value]) => [
|
|
913
|
+
key,
|
|
914
|
+
value.startsWith(".") ? path4.resolve(rootDir, value) : value
|
|
915
|
+
])
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
function uniqueStrings(values) {
|
|
919
|
+
return [...new Set(values)];
|
|
920
|
+
}
|
|
921
|
+
function contentHash(value) {
|
|
922
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
923
|
+
}
|
|
758
924
|
function devSidecarBundleAliases(rootDir) {
|
|
759
925
|
const repoRoot = findSidecarRepoRoot(rootDir) ?? findSidecarRepoRoot(process.cwd());
|
|
760
926
|
if (!repoRoot) {
|
|
761
927
|
return void 0;
|
|
762
928
|
}
|
|
763
|
-
const reactEntry =
|
|
764
|
-
if (!
|
|
929
|
+
const reactEntry = path4.join(repoRoot, "packages", "react", "src", "index.ts");
|
|
930
|
+
if (!existsSync3(reactEntry)) {
|
|
765
931
|
return void 0;
|
|
766
932
|
}
|
|
767
933
|
return {
|
|
768
|
-
"sidecar-ai":
|
|
769
|
-
"@sidecar-ai/client":
|
|
770
|
-
"@sidecar-ai/core":
|
|
934
|
+
"sidecar-ai": path4.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
935
|
+
"@sidecar-ai/client": path4.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
936
|
+
"@sidecar-ai/core": path4.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
771
937
|
"@sidecar-ai/react": reactEntry,
|
|
772
|
-
"@sidecar-ai/native":
|
|
773
|
-
"@sidecar-ai/native/components":
|
|
774
|
-
"@sidecar-ai/native/styles.css":
|
|
938
|
+
"@sidecar-ai/native": path4.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
939
|
+
"@sidecar-ai/native/components": path4.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
940
|
+
"@sidecar-ai/native/styles.css": path4.join(repoRoot, "packages", "native", "src", "styles.css")
|
|
775
941
|
};
|
|
776
942
|
}
|
|
777
943
|
function findSidecarRepoRoot(startDir) {
|
|
778
|
-
let current =
|
|
944
|
+
let current = path4.resolve(startDir);
|
|
779
945
|
while (true) {
|
|
780
|
-
if (
|
|
946
|
+
if (existsSync3(path4.join(current, "packages", "core", "src", "index.ts"))) {
|
|
781
947
|
return current;
|
|
782
948
|
}
|
|
783
|
-
const parent =
|
|
949
|
+
const parent = path4.dirname(current);
|
|
784
950
|
if (parent === current) {
|
|
785
951
|
return void 0;
|
|
786
952
|
}
|
|
@@ -788,13 +954,13 @@ function findSidecarRepoRoot(startDir) {
|
|
|
788
954
|
}
|
|
789
955
|
}
|
|
790
956
|
async function prepareAppStyle(rootDir, cacheDir) {
|
|
791
|
-
const sourceFile =
|
|
792
|
-
if (!
|
|
957
|
+
const sourceFile = path4.join(rootDir, "style.css");
|
|
958
|
+
if (!existsSync3(sourceFile)) {
|
|
793
959
|
return void 0;
|
|
794
960
|
}
|
|
795
961
|
const source = await readFile(sourceFile, "utf8");
|
|
796
962
|
const css = await processAppStyle(source, sourceFile);
|
|
797
|
-
const outputFile =
|
|
963
|
+
const outputFile = path4.join(cacheDir, "style.css");
|
|
798
964
|
await writeFile(outputFile, css);
|
|
799
965
|
return outputFile;
|
|
800
966
|
}
|
|
@@ -806,7 +972,7 @@ async function processAppStyle(source, from) {
|
|
|
806
972
|
const plugins = [];
|
|
807
973
|
if (cssSource.includes("@tailwind")) {
|
|
808
974
|
const tailwind = await import("@tailwindcss/postcss");
|
|
809
|
-
plugins.push(tailwind.default({ base:
|
|
975
|
+
plugins.push(tailwind.default({ base: path4.dirname(from) }));
|
|
810
976
|
}
|
|
811
977
|
const autoprefixer = await import("autoprefixer");
|
|
812
978
|
plugins.push(autoprefixer.default());
|
|
@@ -820,13 +986,13 @@ function needsPostcss(source) {
|
|
|
820
986
|
return /@import\s+["']tailwindcss["']|@tailwind|@source|@theme|@plugin/.test(source);
|
|
821
987
|
}
|
|
822
988
|
function findWidget(rootDir, toolFile, id, target = "mcp", toolVariant = "shared") {
|
|
823
|
-
const selected = selectWidgetFile(
|
|
989
|
+
const selected = selectWidgetFile(path4.dirname(toolFile), target, toolVariant);
|
|
824
990
|
if (!selected) {
|
|
825
991
|
return void 0;
|
|
826
992
|
}
|
|
827
993
|
const safeId = safePathSegment(id);
|
|
828
994
|
return {
|
|
829
|
-
sourceFile:
|
|
995
|
+
sourceFile: path4.relative(rootDir, selected.filePath),
|
|
830
996
|
variant: selected.variant,
|
|
831
997
|
resourceUri: `ui://${safeId}/widget.html`
|
|
832
998
|
};
|
|
@@ -1008,17 +1174,17 @@ function readStringArrayProperty(definition, propertyName) {
|
|
|
1008
1174
|
}
|
|
1009
1175
|
function selectWidgetFile(directory, target, toolVariant) {
|
|
1010
1176
|
if (toolVariant === "openai") {
|
|
1011
|
-
const filePath =
|
|
1012
|
-
return
|
|
1177
|
+
const filePath = path4.join(directory, "widget.openai.tsx");
|
|
1178
|
+
return existsSync3(filePath) ? { filePath, variant: "openai" } : void 0;
|
|
1013
1179
|
}
|
|
1014
1180
|
if (toolVariant === "anthropic") {
|
|
1015
|
-
const filePath =
|
|
1016
|
-
return
|
|
1181
|
+
const filePath = path4.join(directory, "widget.anthropic.tsx");
|
|
1182
|
+
return existsSync3(filePath) ? { filePath, variant: "anthropic" } : void 0;
|
|
1017
1183
|
}
|
|
1018
1184
|
const candidates = target === "chatgpt" || target === "claude" || target === "mcp" ? [{ name: "widget.tsx", variant: "shared" }] : [];
|
|
1019
1185
|
for (const candidate of candidates) {
|
|
1020
|
-
const filePath =
|
|
1021
|
-
if (
|
|
1186
|
+
const filePath = path4.join(directory, candidate.name);
|
|
1187
|
+
if (existsSync3(filePath)) {
|
|
1022
1188
|
return { filePath, variant: candidate.variant };
|
|
1023
1189
|
}
|
|
1024
1190
|
}
|
|
@@ -1069,17 +1235,23 @@ function stripUndefined3(value) {
|
|
|
1069
1235
|
// packages/compiler/src/analyze.ts
|
|
1070
1236
|
async function analyzeProjectTools(rootDir, options = {}) {
|
|
1071
1237
|
const target = options.target ?? "mcp";
|
|
1072
|
-
const toolFiles = await findToolFiles(
|
|
1238
|
+
const toolFiles = await findToolFiles(path5.join(rootDir, "server"), target);
|
|
1073
1239
|
if (toolFiles.length === 0) {
|
|
1074
1240
|
return [];
|
|
1075
1241
|
}
|
|
1076
1242
|
const project = createProject(rootDir);
|
|
1077
1243
|
const authScopes = readAuthScopeCatalog(project, rootDir);
|
|
1078
|
-
|
|
1079
|
-
|
|
1244
|
+
const sources = toolFiles.map((candidate) => ({
|
|
1245
|
+
candidate,
|
|
1246
|
+
sourceFile: project.addSourceFileAtPath(candidate.filePath)
|
|
1247
|
+
}));
|
|
1248
|
+
const runtimeInputSchemas = await readRuntimeInputSchemas(rootDir, sources);
|
|
1249
|
+
return sources.map(
|
|
1250
|
+
({ candidate, sourceFile }) => analyzeToolFile(sourceFile, rootDir, {
|
|
1080
1251
|
target,
|
|
1081
1252
|
variant: candidate.variant,
|
|
1082
|
-
authScopes
|
|
1253
|
+
authScopes,
|
|
1254
|
+
inputSchema: runtimeInputSchemas.get(candidate.filePath)
|
|
1083
1255
|
})
|
|
1084
1256
|
);
|
|
1085
1257
|
}
|
|
@@ -1088,7 +1260,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1088
1260
|
const variant = options.variant ?? "shared";
|
|
1089
1261
|
const definition = findToolDefinition(sourceFile);
|
|
1090
1262
|
const absoluteFile = sourceFile.getFilePath();
|
|
1091
|
-
const directory =
|
|
1263
|
+
const directory = path5.basename(path5.dirname(absoluteFile));
|
|
1092
1264
|
const name = getRequiredStringProperty(definition, "name", sourceFile);
|
|
1093
1265
|
const id = getOptionalStringProperty(definition, "id") ?? toMachineName(directory);
|
|
1094
1266
|
const description = getRequiredStringProperty(
|
|
@@ -1101,7 +1273,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1101
1273
|
const hosts = readHosts(definition);
|
|
1102
1274
|
const auth = readAuthPolicy(definition, options.authScopes ?? {});
|
|
1103
1275
|
const execute = getExecuteFunction(definition, sourceFile);
|
|
1104
|
-
const inputSchema = getParamsSchema(definition, execute);
|
|
1276
|
+
const inputSchema = options.inputSchema ?? getParamsSchema(definition, execute);
|
|
1105
1277
|
const outputSchema = getOutputSchema(definition, execute);
|
|
1106
1278
|
const descriptor = createToolDescriptor({
|
|
1107
1279
|
name,
|
|
@@ -1119,7 +1291,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1119
1291
|
validateWidgetHierarchy(sourceFile, absoluteFile, target, variant);
|
|
1120
1292
|
const widget = findWidget(rootDir, absoluteFile, id, target, variant);
|
|
1121
1293
|
if (widget) {
|
|
1122
|
-
const widgetFile =
|
|
1294
|
+
const widgetFile = path5.join(rootDir, widget.sourceFile);
|
|
1123
1295
|
const project = sourceFile.getProject();
|
|
1124
1296
|
const widgetSourceFile = project.getSourceFile(widgetFile) ?? project.addSourceFileAtPath(widgetFile);
|
|
1125
1297
|
widget.options = {
|
|
@@ -1130,7 +1302,7 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1130
1302
|
descriptor._meta = mergeWidgetMeta(descriptor._meta, widgetMeta(widget.resourceUri, widget.options, target));
|
|
1131
1303
|
}
|
|
1132
1304
|
return {
|
|
1133
|
-
sourceFile:
|
|
1305
|
+
sourceFile: path5.relative(rootDir, absoluteFile),
|
|
1134
1306
|
variant,
|
|
1135
1307
|
target,
|
|
1136
1308
|
directory,
|
|
@@ -1145,6 +1317,26 @@ function analyzeToolFile(sourceFile, rootDir, options = {}) {
|
|
|
1145
1317
|
descriptor
|
|
1146
1318
|
};
|
|
1147
1319
|
}
|
|
1320
|
+
async function readRuntimeInputSchemas(rootDir, sources) {
|
|
1321
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
1322
|
+
await Promise.all(sources.map(async ({ candidate, sourceFile }) => {
|
|
1323
|
+
const definition = findToolDefinition(sourceFile);
|
|
1324
|
+
if (!definitionHasRuntimeParams(definition)) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const schema = await readRuntimeToolInputSchema(rootDir, candidate.filePath);
|
|
1328
|
+
if (schema) {
|
|
1329
|
+
schemas.set(candidate.filePath, schema);
|
|
1330
|
+
}
|
|
1331
|
+
}));
|
|
1332
|
+
return schemas;
|
|
1333
|
+
}
|
|
1334
|
+
function definitionHasRuntimeParams(definition) {
|
|
1335
|
+
if (definition.getProperty("params")) {
|
|
1336
|
+
return true;
|
|
1337
|
+
}
|
|
1338
|
+
return Boolean(getWithParamsCall(definition));
|
|
1339
|
+
}
|
|
1148
1340
|
function readAuthPolicy(definition, authScopes) {
|
|
1149
1341
|
const initializer = readObjectProperty2(definition, "auth");
|
|
1150
1342
|
if (!initializer) {
|
|
@@ -1161,7 +1353,7 @@ function readAuthPolicy(definition, authScopes) {
|
|
|
1161
1353
|
return { authenticated: true };
|
|
1162
1354
|
}
|
|
1163
1355
|
function readAuthScopeCatalog(project, rootDir) {
|
|
1164
|
-
const authPath =
|
|
1356
|
+
const authPath = path5.join(rootDir, "auth.ts");
|
|
1165
1357
|
if (!existsSyncSafe(authPath)) {
|
|
1166
1358
|
return {};
|
|
1167
1359
|
}
|
|
@@ -1243,12 +1435,12 @@ function isNamedCall(call, name) {
|
|
|
1243
1435
|
return callee === name || callee.endsWith(`.${name}`);
|
|
1244
1436
|
}
|
|
1245
1437
|
function validateWidgetHierarchy(sourceFile, toolFile, target, variant) {
|
|
1246
|
-
const directory =
|
|
1438
|
+
const directory = path5.dirname(toolFile);
|
|
1247
1439
|
const platformWidget = target === "chatgpt" ? "widget.openai.tsx" : target === "claude" ? "widget.anthropic.tsx" : void 0;
|
|
1248
1440
|
if (!platformWidget || variant !== "shared") {
|
|
1249
1441
|
return;
|
|
1250
1442
|
}
|
|
1251
|
-
if (existsSyncSafe(
|
|
1443
|
+
if (existsSyncSafe(path5.join(directory, platformWidget))) {
|
|
1252
1444
|
const expectedTool = target === "chatgpt" ? "tool.openai.ts" : "tool.anthropic.ts";
|
|
1253
1445
|
throw new CompilerError(
|
|
1254
1446
|
sourceFile,
|
|
@@ -1263,7 +1455,7 @@ async function findToolFiles(serverDir, target) {
|
|
|
1263
1455
|
const entries = await readdir(serverDir, { withFileTypes: true });
|
|
1264
1456
|
const files = [];
|
|
1265
1457
|
for (const entry of entries) {
|
|
1266
|
-
const entryPath =
|
|
1458
|
+
const entryPath = path5.join(serverDir, entry.name);
|
|
1267
1459
|
if (entry.isDirectory()) {
|
|
1268
1460
|
const candidate = selectToolFile(entryPath, target);
|
|
1269
1461
|
if (candidate) {
|
|
@@ -1282,7 +1474,7 @@ function selectToolFile(directory, target) {
|
|
|
1282
1474
|
{ name: "tool.ts", variant: "shared" }
|
|
1283
1475
|
] : [{ name: "tool.ts", variant: "shared" }];
|
|
1284
1476
|
for (const candidate of candidates) {
|
|
1285
|
-
const filePath =
|
|
1477
|
+
const filePath = path5.join(directory, candidate.name);
|
|
1286
1478
|
if (existsSyncSafe(filePath)) {
|
|
1287
1479
|
return { filePath, variant: candidate.variant };
|
|
1288
1480
|
}
|
|
@@ -1318,16 +1510,32 @@ function getExecuteFunction(definition, sourceFile) {
|
|
|
1318
1510
|
return property;
|
|
1319
1511
|
}
|
|
1320
1512
|
if (Node4.isPropertyAssignment(property)) {
|
|
1321
|
-
const initializer = property.getInitializer();
|
|
1513
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1322
1514
|
if (initializer && (Node4.isArrowFunction(initializer) || Node4.isFunctionExpression(initializer))) {
|
|
1323
1515
|
return initializer;
|
|
1324
1516
|
}
|
|
1517
|
+
const withParamsCall = getWithParamsCall(definition);
|
|
1518
|
+
const wrappedExecute = unwrapExpression(withParamsCall?.getArguments()[1]);
|
|
1519
|
+
if (wrappedExecute && (Node4.isArrowFunction(wrappedExecute) || Node4.isFunctionExpression(wrappedExecute))) {
|
|
1520
|
+
return wrappedExecute;
|
|
1521
|
+
}
|
|
1325
1522
|
}
|
|
1326
1523
|
throw new CompilerError(
|
|
1327
1524
|
sourceFile,
|
|
1328
1525
|
"execute must be a method, function expression, or arrow function."
|
|
1329
1526
|
);
|
|
1330
1527
|
}
|
|
1528
|
+
function getWithParamsCall(definition) {
|
|
1529
|
+
const property = definition.getProperty("execute");
|
|
1530
|
+
if (!property || !Node4.isPropertyAssignment(property)) {
|
|
1531
|
+
return void 0;
|
|
1532
|
+
}
|
|
1533
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1534
|
+
if (!initializer || !Node4.isCallExpression(initializer)) {
|
|
1535
|
+
return void 0;
|
|
1536
|
+
}
|
|
1537
|
+
return isNamedCall(initializer, "withParams") ? initializer : void 0;
|
|
1538
|
+
}
|
|
1331
1539
|
function getRequiredStringProperty(definition, propertyName, sourceFile) {
|
|
1332
1540
|
const value = getOptionalStringProperty(definition, propertyName);
|
|
1333
1541
|
if (value === void 0 || !value.trim()) {
|
|
@@ -1483,16 +1691,16 @@ function readStringArrayProperty2(definition, propertyName) {
|
|
|
1483
1691
|
|
|
1484
1692
|
// packages/compiler/src/build.ts
|
|
1485
1693
|
import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
|
|
1486
|
-
import
|
|
1694
|
+
import path19 from "path";
|
|
1487
1695
|
|
|
1488
1696
|
// packages/compiler/src/config.ts
|
|
1489
|
-
import
|
|
1697
|
+
import path6 from "path";
|
|
1490
1698
|
import {
|
|
1491
1699
|
Node as Node5,
|
|
1492
1700
|
SyntaxKind as SyntaxKind3
|
|
1493
1701
|
} from "ts-morph";
|
|
1494
1702
|
function analyzeProjectConfig(rootDir) {
|
|
1495
|
-
const configPath =
|
|
1703
|
+
const configPath = path6.join(rootDir, "sidecar.config.ts");
|
|
1496
1704
|
if (!existsSyncSafe(configPath)) {
|
|
1497
1705
|
return defaultCompilerConfig();
|
|
1498
1706
|
}
|
|
@@ -1508,7 +1716,8 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1508
1716
|
target: readTargetNested(definition, "build", "target"),
|
|
1509
1717
|
host: readHostNested(definition, "build", "host"),
|
|
1510
1718
|
outDir: readStringNested(definition, "build", "outDir"),
|
|
1511
|
-
plugins: readBooleanNested(definition, "build", "plugins")
|
|
1719
|
+
plugins: readBooleanNested(definition, "build", "plugins"),
|
|
1720
|
+
widgets: readWidgetBuildConfig(definition)
|
|
1512
1721
|
},
|
|
1513
1722
|
resources: {
|
|
1514
1723
|
subscribe: readBooleanNested(definition, "resources", "subscribe") ?? false,
|
|
@@ -1526,6 +1735,44 @@ function analyzeProjectConfig(rootDir) {
|
|
|
1526
1735
|
}
|
|
1527
1736
|
};
|
|
1528
1737
|
}
|
|
1738
|
+
function readWidgetBuildConfig(definition) {
|
|
1739
|
+
const widgets = readObjectProperty3(readObjectProperty3(definition, "build"), "widgets");
|
|
1740
|
+
if (!widgets) {
|
|
1741
|
+
return void 0;
|
|
1742
|
+
}
|
|
1743
|
+
const config = {};
|
|
1744
|
+
const configure = readStringProperty3(widgets, "configure");
|
|
1745
|
+
const esbuild3 = readWidgetEsbuildConfig(widgets);
|
|
1746
|
+
if (configure) config.configure = configure;
|
|
1747
|
+
if (esbuild3) config.esbuild = esbuild3;
|
|
1748
|
+
return Object.keys(config).length ? config : void 0;
|
|
1749
|
+
}
|
|
1750
|
+
function readWidgetEsbuildConfig(widgets) {
|
|
1751
|
+
const esbuild3 = readObjectProperty3(widgets, "esbuild");
|
|
1752
|
+
if (!esbuild3) {
|
|
1753
|
+
return void 0;
|
|
1754
|
+
}
|
|
1755
|
+
const config = {};
|
|
1756
|
+
const alias = readStringRecordProperty(esbuild3, "alias");
|
|
1757
|
+
const define = readStringRecordProperty(esbuild3, "define");
|
|
1758
|
+
const external = readStringArrayProperty3(esbuild3, "external");
|
|
1759
|
+
const loader = readStringRecordProperty(esbuild3, "loader");
|
|
1760
|
+
const conditions = readStringArrayProperty3(esbuild3, "conditions");
|
|
1761
|
+
const mainFields = readStringArrayProperty3(esbuild3, "mainFields");
|
|
1762
|
+
const jsx = readStringProperty3(esbuild3, "jsx");
|
|
1763
|
+
const jsxImportSource = readStringProperty3(esbuild3, "jsxImportSource");
|
|
1764
|
+
if (alias) config.alias = alias;
|
|
1765
|
+
if (define) config.define = define;
|
|
1766
|
+
if (external) config.external = external;
|
|
1767
|
+
if (loader) config.loader = loader;
|
|
1768
|
+
if (conditions) config.conditions = conditions;
|
|
1769
|
+
if (mainFields) config.mainFields = mainFields;
|
|
1770
|
+
if (jsx === "automatic" || jsx === "transform" || jsx === "preserve") {
|
|
1771
|
+
config.jsx = jsx;
|
|
1772
|
+
}
|
|
1773
|
+
if (jsxImportSource) config.jsxImportSource = jsxImportSource;
|
|
1774
|
+
return Object.keys(config).length ? config : void 0;
|
|
1775
|
+
}
|
|
1529
1776
|
function defaultCompilerConfig() {
|
|
1530
1777
|
return {
|
|
1531
1778
|
build: {},
|
|
@@ -1558,12 +1805,7 @@ function readStringNested(definition, section, propertyName) {
|
|
|
1558
1805
|
if (!object) {
|
|
1559
1806
|
return void 0;
|
|
1560
1807
|
}
|
|
1561
|
-
|
|
1562
|
-
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1563
|
-
return void 0;
|
|
1564
|
-
}
|
|
1565
|
-
const initializer = unwrapExpression(property.getInitializer());
|
|
1566
|
-
return initializer && Node5.isStringLiteral(initializer) ? initializer.getLiteralText() : void 0;
|
|
1808
|
+
return readStringProperty3(object, propertyName);
|
|
1567
1809
|
}
|
|
1568
1810
|
function readBooleanNested(definition, section, propertyName) {
|
|
1569
1811
|
const object = readObjectProperty3(definition, section);
|
|
@@ -1595,6 +1837,9 @@ function readNumberNested(definition, section, propertyName) {
|
|
|
1595
1837
|
return initializer && Node5.isNumericLiteral(initializer) ? Number(initializer.getLiteralText()) : void 0;
|
|
1596
1838
|
}
|
|
1597
1839
|
function readObjectProperty3(definition, propertyName) {
|
|
1840
|
+
if (!definition) {
|
|
1841
|
+
return void 0;
|
|
1842
|
+
}
|
|
1598
1843
|
const property = definition.getProperty(propertyName);
|
|
1599
1844
|
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1600
1845
|
return void 0;
|
|
@@ -1602,38 +1847,79 @@ function readObjectProperty3(definition, propertyName) {
|
|
|
1602
1847
|
const initializer = unwrapExpression(property.getInitializer());
|
|
1603
1848
|
return initializer && Node5.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
1604
1849
|
}
|
|
1850
|
+
function readStringProperty3(definition, propertyName) {
|
|
1851
|
+
const property = definition.getProperty(propertyName);
|
|
1852
|
+
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1853
|
+
return void 0;
|
|
1854
|
+
}
|
|
1855
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1856
|
+
return initializer && Node5.isStringLiteral(initializer) ? initializer.getLiteralText() : void 0;
|
|
1857
|
+
}
|
|
1858
|
+
function readStringArrayProperty3(definition, propertyName) {
|
|
1859
|
+
const property = definition.getProperty(propertyName);
|
|
1860
|
+
if (!property || !Node5.isPropertyAssignment(property)) {
|
|
1861
|
+
return void 0;
|
|
1862
|
+
}
|
|
1863
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1864
|
+
if (!initializer || !Node5.isArrayLiteralExpression(initializer)) {
|
|
1865
|
+
return void 0;
|
|
1866
|
+
}
|
|
1867
|
+
const values = initializer.getElements().map((element) => {
|
|
1868
|
+
const unwrapped = unwrapExpression(element);
|
|
1869
|
+
return unwrapped && Node5.isStringLiteral(unwrapped) ? unwrapped.getLiteralText() : void 0;
|
|
1870
|
+
});
|
|
1871
|
+
return values.every((value) => value !== void 0) ? values : void 0;
|
|
1872
|
+
}
|
|
1873
|
+
function readStringRecordProperty(definition, propertyName) {
|
|
1874
|
+
const object = readObjectProperty3(definition, propertyName);
|
|
1875
|
+
if (!object) {
|
|
1876
|
+
return void 0;
|
|
1877
|
+
}
|
|
1878
|
+
const record = {};
|
|
1879
|
+
for (const property of object.getProperties()) {
|
|
1880
|
+
if (!Node5.isPropertyAssignment(property)) {
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
const initializer = unwrapExpression(property.getInitializer());
|
|
1884
|
+
if (!initializer || !Node5.isStringLiteral(initializer)) {
|
|
1885
|
+
return void 0;
|
|
1886
|
+
}
|
|
1887
|
+
record[property.getName().replace(/^["']|["']$/g, "")] = initializer.getLiteralText();
|
|
1888
|
+
}
|
|
1889
|
+
return record;
|
|
1890
|
+
}
|
|
1605
1891
|
function hasProperty(definition, propertyName) {
|
|
1606
1892
|
return Boolean(definition?.getProperty(propertyName));
|
|
1607
1893
|
}
|
|
1608
1894
|
|
|
1609
1895
|
// packages/compiler/src/diagnostics.ts
|
|
1610
|
-
import { existsSync as
|
|
1896
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1611
1897
|
import { readFile as readFile2 } from "fs/promises";
|
|
1612
|
-
import
|
|
1898
|
+
import path7 from "path";
|
|
1613
1899
|
async function collectProjectDiagnostics(rootDir, input) {
|
|
1614
1900
|
const diagnostics = [];
|
|
1615
1901
|
const tools = Array.isArray(input) ? input : input.tools;
|
|
1616
1902
|
const resources = Array.isArray(input) ? [] : input.resources ?? [];
|
|
1617
1903
|
const prompts = Array.isArray(input) ? [] : input.prompts ?? [];
|
|
1618
1904
|
const config = Array.isArray(input) ? void 0 : input.config;
|
|
1619
|
-
const hasAuthConfig =
|
|
1905
|
+
const hasAuthConfig = existsSync4(path7.join(rootDir, "auth.ts"));
|
|
1620
1906
|
for (const entry of tools) {
|
|
1621
|
-
const toolPath =
|
|
1907
|
+
const toolPath = path7.join(rootDir, entry.sourceFile);
|
|
1622
1908
|
const toolSource = await readFile2(toolPath, "utf8");
|
|
1623
|
-
diagnostics.push(...diagnoseToolSource(
|
|
1909
|
+
diagnostics.push(...diagnoseToolSource(entry, toolSource, hasAuthConfig));
|
|
1624
1910
|
if (entry.widget) {
|
|
1625
|
-
const widgetPath =
|
|
1911
|
+
const widgetPath = path7.join(rootDir, entry.widget.sourceFile);
|
|
1626
1912
|
const widgetSource = await readFile2(widgetPath, "utf8");
|
|
1627
1913
|
diagnostics.push(...diagnoseWidgetSource(rootDir, entry, widgetSource));
|
|
1628
1914
|
}
|
|
1629
1915
|
}
|
|
1630
1916
|
for (const entry of resources) {
|
|
1631
|
-
const resourcePath =
|
|
1917
|
+
const resourcePath = path7.join(rootDir, entry.sourceFile);
|
|
1632
1918
|
const resourceSource = await readFile2(resourcePath, "utf8");
|
|
1633
1919
|
diagnostics.push(...diagnoseResourceSource(entry, resourceSource));
|
|
1634
1920
|
}
|
|
1635
1921
|
for (const entry of prompts) {
|
|
1636
|
-
const promptPath =
|
|
1922
|
+
const promptPath = path7.join(rootDir, entry.sourceFile);
|
|
1637
1923
|
const promptSource = await readFile2(promptPath, "utf8");
|
|
1638
1924
|
diagnostics.push(...diagnosePromptSource(entry, promptSource));
|
|
1639
1925
|
}
|
|
@@ -1648,7 +1934,7 @@ function formatDiagnostic(diagnostic) {
|
|
|
1648
1934
|
hint: ${diagnostic.hint}` : "";
|
|
1649
1935
|
return `${location} - ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}${hint}`;
|
|
1650
1936
|
}
|
|
1651
|
-
function diagnoseToolSource(
|
|
1937
|
+
function diagnoseToolSource(entry, source, hasAuthConfig) {
|
|
1652
1938
|
const diagnostics = [];
|
|
1653
1939
|
const toolLocation = locate(source, "tool({");
|
|
1654
1940
|
if (!entry.description.trim().startsWith("Use this when")) {
|
|
@@ -1865,21 +2151,21 @@ function isIgnored(source, code) {
|
|
|
1865
2151
|
|
|
1866
2152
|
// packages/compiler/src/generated.ts
|
|
1867
2153
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
1868
|
-
import
|
|
2154
|
+
import path8 from "path";
|
|
1869
2155
|
async function writeGeneratedTypes(rootDir, tools) {
|
|
1870
|
-
const generatedDir =
|
|
2156
|
+
const generatedDir = path8.join(rootDir, ".sidecar", "generated");
|
|
1871
2157
|
await mkdir2(generatedDir, { recursive: true });
|
|
1872
2158
|
const appCallableTools = tools.filter(isAppCallable);
|
|
1873
2159
|
const methodNames = uniqueMethodNames(appCallableTools.map((entry) => toIdentifier(entry.id)));
|
|
1874
2160
|
const imports = appCallableTools.map(
|
|
1875
|
-
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir,
|
|
2161
|
+
(entry, index) => `import type tool${index} from ${JSON.stringify(toImportSpecifier(generatedDir, path8.join(rootDir, entry.sourceFile), { extension: "js" }))};`
|
|
1876
2162
|
).join("\n");
|
|
1877
2163
|
const ids = appCallableTools.map((entry, index) => ` ${methodNames[index]}: ${JSON.stringify(entry.id)}`).join(",\n");
|
|
1878
2164
|
const toolTypes = appCallableTools.map(
|
|
1879
|
-
(
|
|
2165
|
+
(_entry, index) => ` ${methodNames[index]}(params: ToolParams<typeof tool${index}>): Promise<ToolOutput<typeof tool${index}>>;`
|
|
1880
2166
|
).join("\n");
|
|
1881
2167
|
await writeFile2(
|
|
1882
|
-
|
|
2168
|
+
path8.join(generatedDir, "tools.ts"),
|
|
1883
2169
|
`/**
|
|
1884
2170
|
* Generated Sidecar widget tool client.
|
|
1885
2171
|
*
|
|
@@ -1929,13 +2215,13 @@ function uniqueMethodNames(names) {
|
|
|
1929
2215
|
|
|
1930
2216
|
// packages/compiler/src/identity.ts
|
|
1931
2217
|
import { readFile as readFile3 } from "fs/promises";
|
|
1932
|
-
import
|
|
2218
|
+
import path9 from "path";
|
|
1933
2219
|
async function loadProjectIdentity(rootDir) {
|
|
1934
|
-
const packageJson = await readOptionalJson(
|
|
2220
|
+
const packageJson = await readOptionalJson(path9.join(rootDir, "package.json"));
|
|
1935
2221
|
const configText = await readOptionalText(
|
|
1936
|
-
|
|
2222
|
+
path9.join(rootDir, "sidecar.config.ts")
|
|
1937
2223
|
);
|
|
1938
|
-
const name = readConfigString(configText, "name") ?? packageJson?.name ??
|
|
2224
|
+
const name = readConfigString(configText, "name") ?? packageJson?.name ?? path9.basename(rootDir);
|
|
1939
2225
|
const version = readConfigString(configText, "version") ?? packageJson?.version ?? "0.0.0-dev";
|
|
1940
2226
|
const description = readConfigString(configText, "description") ?? packageJson?.description ?? `${name} Sidecar app.`;
|
|
1941
2227
|
return {
|
|
@@ -1969,32 +2255,32 @@ function readConfigString(configText, key) {
|
|
|
1969
2255
|
|
|
1970
2256
|
// packages/compiler/src/plugins.ts
|
|
1971
2257
|
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
1972
|
-
import
|
|
2258
|
+
import path15 from "path";
|
|
1973
2259
|
|
|
1974
2260
|
// packages/compiler/src/plugin-components/agents.ts
|
|
1975
2261
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
1976
|
-
import
|
|
2262
|
+
import path10 from "path";
|
|
1977
2263
|
async function emitClaudeAgents(rootDir, destination) {
|
|
1978
|
-
const source =
|
|
2264
|
+
const source = path10.join(rootDir, "agents");
|
|
1979
2265
|
if (!existsSyncSafe(source)) {
|
|
1980
2266
|
return;
|
|
1981
2267
|
}
|
|
1982
2268
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
1983
2269
|
const agentDirs = entries.filter(
|
|
1984
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
2270
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path10.join(source, entry.name, "agent.ts"))
|
|
1985
2271
|
);
|
|
1986
2272
|
if (!agentDirs.length) {
|
|
1987
2273
|
return;
|
|
1988
2274
|
}
|
|
1989
2275
|
await mkdir3(destination, { recursive: true });
|
|
1990
2276
|
for (const entry of agentDirs) {
|
|
1991
|
-
const sourceText = await readFile4(
|
|
2277
|
+
const sourceText = await readFile4(path10.join(source, entry.name, "agent.ts"), "utf8");
|
|
1992
2278
|
const markdown = parseClaudeAgent(
|
|
1993
2279
|
sourceText,
|
|
1994
2280
|
entry.name
|
|
1995
2281
|
);
|
|
1996
2282
|
const agentName = readObjectString(sourceText, "name") ?? entry.name;
|
|
1997
|
-
await writeFile3(
|
|
2283
|
+
await writeFile3(path10.join(destination, `${safeFileStem(agentName)}.md`), markdown);
|
|
1998
2284
|
}
|
|
1999
2285
|
}
|
|
2000
2286
|
function parseClaudeAgent(source, fallbackName) {
|
|
@@ -2023,41 +2309,41 @@ ${prompt.trim()}
|
|
|
2023
2309
|
|
|
2024
2310
|
// packages/compiler/src/plugin-components/commands.ts
|
|
2025
2311
|
import { cp, lstat, mkdir as mkdir4, readdir as readdir3, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
2026
|
-
import
|
|
2312
|
+
import path11 from "path";
|
|
2027
2313
|
async function copyCommands(rootDir, destination) {
|
|
2028
|
-
const source =
|
|
2314
|
+
const source = path11.join(rootDir, "commands");
|
|
2029
2315
|
if (!existsSyncSafe(source)) {
|
|
2030
2316
|
return;
|
|
2031
2317
|
}
|
|
2032
2318
|
await mkdir4(destination, { recursive: true });
|
|
2033
2319
|
const entries = await readdir3(source, { withFileTypes: true });
|
|
2034
2320
|
for (const entry of entries) {
|
|
2035
|
-
const sourcePath =
|
|
2321
|
+
const sourcePath = path11.join(source, entry.name);
|
|
2036
2322
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2037
2323
|
if (await safeCommandCopyFilter(sourcePath)) {
|
|
2038
|
-
await cp(sourcePath,
|
|
2324
|
+
await cp(sourcePath, path11.join(destination, safeFileStem(entry.name.replace(/\.md$/, "")) + ".md"));
|
|
2039
2325
|
}
|
|
2040
2326
|
continue;
|
|
2041
2327
|
}
|
|
2042
2328
|
if (!entry.isDirectory()) {
|
|
2043
2329
|
continue;
|
|
2044
2330
|
}
|
|
2045
|
-
const dynamicCommand =
|
|
2331
|
+
const dynamicCommand = path11.join(sourcePath, "command.ts");
|
|
2046
2332
|
if (existsSyncSafe(dynamicCommand)) {
|
|
2047
2333
|
const sourceText = await readFile5(dynamicCommand, "utf8");
|
|
2048
2334
|
const markdown = parseDynamicCommand(sourceText, entry.name);
|
|
2049
2335
|
const commandName = readObjectString(sourceText, "name") ?? entry.name;
|
|
2050
|
-
await writeFile4(
|
|
2336
|
+
await writeFile4(path11.join(destination, `${safeFileStem(commandName)}.md`), markdown);
|
|
2051
2337
|
continue;
|
|
2052
2338
|
}
|
|
2053
|
-
await cp(sourcePath,
|
|
2339
|
+
await cp(sourcePath, path11.join(destination, entry.name), {
|
|
2054
2340
|
recursive: true,
|
|
2055
2341
|
filter: safeCommandCopyFilter
|
|
2056
2342
|
});
|
|
2057
2343
|
}
|
|
2058
2344
|
}
|
|
2059
2345
|
async function safeCommandCopyFilter(sourcePath) {
|
|
2060
|
-
const basename =
|
|
2346
|
+
const basename = path11.basename(sourcePath);
|
|
2061
2347
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2062
2348
|
return false;
|
|
2063
2349
|
}
|
|
@@ -2086,32 +2372,32 @@ ${Object.entries(frontmatter).map(([key, value]) => `${key}: ${yamlScalar(value)
|
|
|
2086
2372
|
|
|
2087
2373
|
// packages/compiler/src/plugin-components/hooks.ts
|
|
2088
2374
|
import { mkdir as mkdir5, readdir as readdir4, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
2089
|
-
import
|
|
2375
|
+
import path12 from "path";
|
|
2090
2376
|
import {
|
|
2091
2377
|
Node as Node6,
|
|
2092
2378
|
Project as Project2,
|
|
2093
2379
|
SyntaxKind as SyntaxKind4
|
|
2094
2380
|
} from "ts-morph";
|
|
2095
2381
|
async function copyHooks(rootDir, destination) {
|
|
2096
|
-
const source =
|
|
2382
|
+
const source = path12.join(rootDir, "hooks");
|
|
2097
2383
|
if (!existsSyncSafe(source)) {
|
|
2098
2384
|
return;
|
|
2099
2385
|
}
|
|
2100
2386
|
const entries = await readdir4(source, { withFileTypes: true });
|
|
2101
2387
|
const hookDirs = entries.filter(
|
|
2102
|
-
(entry) => entry.isDirectory() && existsSyncSafe(
|
|
2388
|
+
(entry) => entry.isDirectory() && existsSyncSafe(path12.join(source, entry.name, "hook.ts"))
|
|
2103
2389
|
);
|
|
2104
2390
|
if (!hookDirs.length) {
|
|
2105
2391
|
return;
|
|
2106
2392
|
}
|
|
2107
2393
|
const config = {};
|
|
2108
2394
|
for (const entry of hookDirs) {
|
|
2109
|
-
const filePath =
|
|
2395
|
+
const filePath = path12.join(source, entry.name, "hook.ts");
|
|
2110
2396
|
mergeHooks(config, parseHookFile(await readFile6(filePath, "utf8"), entry.name));
|
|
2111
2397
|
}
|
|
2112
2398
|
await mkdir5(destination, { recursive: true });
|
|
2113
2399
|
await writeFile5(
|
|
2114
|
-
|
|
2400
|
+
path12.join(destination, "hooks.json"),
|
|
2115
2401
|
`${JSON.stringify(config, null, 2)}
|
|
2116
2402
|
`
|
|
2117
2403
|
);
|
|
@@ -2138,7 +2424,7 @@ function parseHookFile(source, fallbackName) {
|
|
|
2138
2424
|
throw new Error(`hooks/${fallbackName}/hook.ts must default-export hook({ ... }) or hooks({ ... }).`);
|
|
2139
2425
|
}
|
|
2140
2426
|
function parseHookDefinition(definition, fallbackName) {
|
|
2141
|
-
const event =
|
|
2427
|
+
const event = readStringProperty4(definition, "event");
|
|
2142
2428
|
if (!event) {
|
|
2143
2429
|
throw new Error(`hooks/${fallbackName}/hook.ts must declare an event string.`);
|
|
2144
2430
|
}
|
|
@@ -2148,7 +2434,7 @@ function parseHookDefinition(definition, fallbackName) {
|
|
|
2148
2434
|
}
|
|
2149
2435
|
return {
|
|
2150
2436
|
event,
|
|
2151
|
-
matcher:
|
|
2437
|
+
matcher: readStringProperty4(definition, "matcher"),
|
|
2152
2438
|
run: hooks
|
|
2153
2439
|
};
|
|
2154
2440
|
}
|
|
@@ -2168,7 +2454,7 @@ function parseHooksDefinition(definition, fallbackName) {
|
|
|
2168
2454
|
throw new Error(`hooks/${fallbackName}/hook.ts event "${event}" entries must be objects.`);
|
|
2169
2455
|
}
|
|
2170
2456
|
return stripUndefined2({
|
|
2171
|
-
matcher:
|
|
2457
|
+
matcher: readStringProperty4(entry, "matcher"),
|
|
2172
2458
|
hooks: readHookArray(entry, "run", fallbackName)
|
|
2173
2459
|
});
|
|
2174
2460
|
});
|
|
@@ -2191,7 +2477,7 @@ function parseHookHandlers(handlers, fallbackName) {
|
|
|
2191
2477
|
}
|
|
2192
2478
|
function parseHookHandler(handler, fallbackName) {
|
|
2193
2479
|
if (Node6.isObjectLiteralExpression(handler)) {
|
|
2194
|
-
const type =
|
|
2480
|
+
const type = readStringProperty4(handler, "type");
|
|
2195
2481
|
if (type !== "command" && type !== "http") {
|
|
2196
2482
|
throw new Error(`hooks/${fallbackName}/hook.ts hook handlers need type "command" or "http".`);
|
|
2197
2483
|
}
|
|
@@ -2241,7 +2527,7 @@ function objectLiteralToRecord(object) {
|
|
|
2241
2527
|
}
|
|
2242
2528
|
return stripUndefined2(record);
|
|
2243
2529
|
}
|
|
2244
|
-
function
|
|
2530
|
+
function readStringProperty4(object, propertyName) {
|
|
2245
2531
|
const property = object.getProperty(propertyName);
|
|
2246
2532
|
if (!property || !Node6.isPropertyAssignment(property)) {
|
|
2247
2533
|
return void 0;
|
|
@@ -2285,7 +2571,7 @@ function mergeHooks(target, source) {
|
|
|
2285
2571
|
|
|
2286
2572
|
// packages/compiler/src/plugin-components/passthrough.ts
|
|
2287
2573
|
import { cp as cp2, lstat as lstat2 } from "fs/promises";
|
|
2288
|
-
import
|
|
2574
|
+
import path13 from "path";
|
|
2289
2575
|
async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
2290
2576
|
for (const directory of [
|
|
2291
2577
|
"assets",
|
|
@@ -2294,18 +2580,18 @@ async function copyClaudePassthroughDirectories(rootDir, pluginDir) {
|
|
|
2294
2580
|
"output-styles",
|
|
2295
2581
|
"themes"
|
|
2296
2582
|
]) {
|
|
2297
|
-
const source =
|
|
2583
|
+
const source = path13.join(rootDir, directory);
|
|
2298
2584
|
if (!existsSyncSafe(source)) {
|
|
2299
2585
|
continue;
|
|
2300
2586
|
}
|
|
2301
|
-
await cp2(source,
|
|
2587
|
+
await cp2(source, path13.join(pluginDir, directory), {
|
|
2302
2588
|
recursive: true,
|
|
2303
2589
|
filter: safePluginCopyFilter
|
|
2304
2590
|
});
|
|
2305
2591
|
}
|
|
2306
2592
|
}
|
|
2307
2593
|
async function safePluginCopyFilter(sourcePath) {
|
|
2308
|
-
const basename =
|
|
2594
|
+
const basename = path13.basename(sourcePath);
|
|
2309
2595
|
if (basename === "node_modules" || basename === ".git" || basename === ".env" || basename.startsWith(".env.")) {
|
|
2310
2596
|
return false;
|
|
2311
2597
|
}
|
|
@@ -2314,11 +2600,11 @@ async function safePluginCopyFilter(sourcePath) {
|
|
|
2314
2600
|
}
|
|
2315
2601
|
|
|
2316
2602
|
// packages/compiler/src/plugin-components/skills.ts
|
|
2317
|
-
import { existsSync as
|
|
2603
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2318
2604
|
import { cp as cp3, lstat as lstat3, mkdir as mkdir6, readdir as readdir5, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
2319
|
-
import
|
|
2605
|
+
import path14 from "path";
|
|
2320
2606
|
async function copySkills(rootDir, destination) {
|
|
2321
|
-
const source =
|
|
2607
|
+
const source = path14.join(rootDir, "skills");
|
|
2322
2608
|
if (!existsSyncSafe(source)) {
|
|
2323
2609
|
return;
|
|
2324
2610
|
}
|
|
@@ -2328,27 +2614,27 @@ async function copySkills(rootDir, destination) {
|
|
|
2328
2614
|
if (!entry.isDirectory()) {
|
|
2329
2615
|
continue;
|
|
2330
2616
|
}
|
|
2331
|
-
const sourceDir =
|
|
2332
|
-
const destinationDir =
|
|
2333
|
-
const staticSkill =
|
|
2334
|
-
const dynamicSkill =
|
|
2617
|
+
const sourceDir = path14.join(source, entry.name);
|
|
2618
|
+
const destinationDir = path14.join(destination, entry.name);
|
|
2619
|
+
const staticSkill = path14.join(sourceDir, "SKILL.md");
|
|
2620
|
+
const dynamicSkill = path14.join(sourceDir, "skill.ts");
|
|
2335
2621
|
await mkdir6(destinationDir, { recursive: true });
|
|
2336
|
-
if (
|
|
2622
|
+
if (existsSync5(staticSkill)) {
|
|
2337
2623
|
await cp3(sourceDir, destinationDir, {
|
|
2338
2624
|
recursive: true,
|
|
2339
|
-
filter: async (sourcePath) => !sourcePath.endsWith(`${
|
|
2625
|
+
filter: async (sourcePath) => !sourcePath.endsWith(`${path14.sep}skill.ts`) && await safeSkillCopyFilter(sourcePath)
|
|
2340
2626
|
});
|
|
2341
|
-
} else if (
|
|
2627
|
+
} else if (existsSync5(dynamicSkill)) {
|
|
2342
2628
|
const generated = parseDynamicSkill(
|
|
2343
2629
|
await readFile7(dynamicSkill, "utf8"),
|
|
2344
2630
|
entry.name
|
|
2345
2631
|
);
|
|
2346
|
-
await writeFile6(
|
|
2632
|
+
await writeFile6(path14.join(destinationDir, "SKILL.md"), generated);
|
|
2347
2633
|
}
|
|
2348
2634
|
}
|
|
2349
2635
|
}
|
|
2350
2636
|
async function safeSkillCopyFilter(sourcePath) {
|
|
2351
|
-
const basename =
|
|
2637
|
+
const basename = path14.basename(sourcePath);
|
|
2352
2638
|
if (basename === ".env" || basename.startsWith(".env.") || basename === "node_modules" || basename === ".git") {
|
|
2353
2639
|
return false;
|
|
2354
2640
|
}
|
|
@@ -2374,25 +2660,25 @@ async function buildPluginPackages(rootDir, outRoot, manifest) {
|
|
|
2374
2660
|
await buildClaudePlugin(rootDir, outRoot, identity, manifest);
|
|
2375
2661
|
}
|
|
2376
2662
|
async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
2377
|
-
const pluginDir =
|
|
2378
|
-
await mkdir7(
|
|
2379
|
-
await copySkills(rootDir,
|
|
2380
|
-
await copyCommands(rootDir,
|
|
2381
|
-
await copyHooks(rootDir,
|
|
2382
|
-
await emitClaudeAgents(rootDir,
|
|
2663
|
+
const pluginDir = path15.join(outRoot, "claude-plugin");
|
|
2664
|
+
await mkdir7(path15.join(pluginDir, ".claude-plugin"), { recursive: true });
|
|
2665
|
+
await copySkills(rootDir, path15.join(pluginDir, "skills"));
|
|
2666
|
+
await copyCommands(rootDir, path15.join(pluginDir, "commands"));
|
|
2667
|
+
await copyHooks(rootDir, path15.join(pluginDir, "hooks"));
|
|
2668
|
+
await emitClaudeAgents(rootDir, path15.join(pluginDir, "agents"));
|
|
2383
2669
|
await copyClaudePassthroughDirectories(rootDir, pluginDir);
|
|
2384
|
-
await writeJson(
|
|
2670
|
+
await writeJson(path15.join(pluginDir, ".claude-plugin", "plugin.json"), {
|
|
2385
2671
|
name: identity.slug,
|
|
2386
2672
|
version: identity.version,
|
|
2387
2673
|
description: identity.description,
|
|
2388
2674
|
displayName: identity.name,
|
|
2389
2675
|
installationPreference: "available"
|
|
2390
2676
|
});
|
|
2391
|
-
await writeJson(
|
|
2677
|
+
await writeJson(path15.join(pluginDir, "version.json"), {
|
|
2392
2678
|
version: identity.version,
|
|
2393
2679
|
generatedBy: "sidecar"
|
|
2394
2680
|
});
|
|
2395
|
-
await writeJson(
|
|
2681
|
+
await writeJson(path15.join(pluginDir, ".mcp.json"), {
|
|
2396
2682
|
mcpServers: {
|
|
2397
2683
|
[identity.slug]: {
|
|
2398
2684
|
type: "http",
|
|
@@ -2400,7 +2686,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2400
2686
|
}
|
|
2401
2687
|
}
|
|
2402
2688
|
});
|
|
2403
|
-
await writeJson(
|
|
2689
|
+
await writeJson(path15.join(pluginDir, "settings.json"), {
|
|
2404
2690
|
sidecar: {
|
|
2405
2691
|
tools: manifest.tools.map((entry) => entry.id),
|
|
2406
2692
|
resources: manifest.resources.map((entry) => entry.uri),
|
|
@@ -2408,7 +2694,7 @@ async function buildClaudePlugin(rootDir, outRoot, identity, manifest) {
|
|
|
2408
2694
|
}
|
|
2409
2695
|
});
|
|
2410
2696
|
await writeFile7(
|
|
2411
|
-
|
|
2697
|
+
path15.join(pluginDir, "README.md"),
|
|
2412
2698
|
`# ${identity.name} Claude Plugin
|
|
2413
2699
|
|
|
2414
2700
|
This package was generated by Sidecar.
|
|
@@ -2422,7 +2708,7 @@ Claude/Cowork plugin-specific components such as skills, slash commands, agents,
|
|
|
2422
2708
|
);
|
|
2423
2709
|
}
|
|
2424
2710
|
async function writeJson(filePath, value) {
|
|
2425
|
-
await mkdir7(
|
|
2711
|
+
await mkdir7(path15.dirname(filePath), { recursive: true });
|
|
2426
2712
|
await writeFile7(
|
|
2427
2713
|
filePath,
|
|
2428
2714
|
`${JSON.stringify(stripUndefined2(value), null, 2)}
|
|
@@ -2432,13 +2718,13 @@ async function writeJson(filePath, value) {
|
|
|
2432
2718
|
|
|
2433
2719
|
// packages/compiler/src/prompts.ts
|
|
2434
2720
|
import { readdir as readdir6 } from "fs/promises";
|
|
2435
|
-
import
|
|
2721
|
+
import path16 from "path";
|
|
2436
2722
|
import {
|
|
2437
2723
|
Node as Node7,
|
|
2438
2724
|
SyntaxKind as SyntaxKind5
|
|
2439
2725
|
} from "ts-morph";
|
|
2440
2726
|
async function analyzeProjectPrompts(rootDir) {
|
|
2441
|
-
const promptFiles = await findPromptFiles(
|
|
2727
|
+
const promptFiles = await findPromptFiles(path16.join(rootDir, "prompts"));
|
|
2442
2728
|
if (promptFiles.length === 0) {
|
|
2443
2729
|
return [];
|
|
2444
2730
|
}
|
|
@@ -2450,7 +2736,7 @@ async function analyzeProjectPrompts(rootDir) {
|
|
|
2450
2736
|
function analyzePromptFile(sourceFile, rootDir) {
|
|
2451
2737
|
const definition = findPromptDefinition(sourceFile);
|
|
2452
2738
|
const absoluteFile = sourceFile.getFilePath();
|
|
2453
|
-
const directory =
|
|
2739
|
+
const directory = path16.basename(path16.dirname(absoluteFile));
|
|
2454
2740
|
const name = getOptionalStringProperty2(definition, "name") ?? safePathSegment(directory);
|
|
2455
2741
|
const title = getRequiredStringProperty2(definition, "title", sourceFile);
|
|
2456
2742
|
const description = getOptionalStringProperty2(definition, "description");
|
|
@@ -2466,7 +2752,7 @@ function analyzePromptFile(sourceFile, rootDir) {
|
|
|
2466
2752
|
throw new CompilerError(sourceFile, "prompt({ ... }) must include a run method.");
|
|
2467
2753
|
}
|
|
2468
2754
|
return {
|
|
2469
|
-
sourceFile:
|
|
2755
|
+
sourceFile: path16.relative(rootDir, absoluteFile),
|
|
2470
2756
|
directory,
|
|
2471
2757
|
name,
|
|
2472
2758
|
title,
|
|
@@ -2485,7 +2771,7 @@ async function findPromptFiles(promptsDir) {
|
|
|
2485
2771
|
if (!entry.isDirectory()) {
|
|
2486
2772
|
continue;
|
|
2487
2773
|
}
|
|
2488
|
-
const filePath =
|
|
2774
|
+
const filePath = path16.join(promptsDir, entry.name, "prompt.ts");
|
|
2489
2775
|
if (existsSyncSafe(filePath)) {
|
|
2490
2776
|
files.push(filePath);
|
|
2491
2777
|
}
|
|
@@ -2607,7 +2893,7 @@ function readIcons(definition) {
|
|
|
2607
2893
|
return [{
|
|
2608
2894
|
src,
|
|
2609
2895
|
mimeType: getOptionalStringProperty2(object, "mimeType"),
|
|
2610
|
-
sizes:
|
|
2896
|
+
sizes: readStringArrayProperty4(object, "sizes")
|
|
2611
2897
|
}];
|
|
2612
2898
|
});
|
|
2613
2899
|
return icons.length ? icons : void 0;
|
|
@@ -2620,7 +2906,7 @@ function readObjectProperty4(definition, propertyName) {
|
|
|
2620
2906
|
const initializer = unwrapExpression(property.getInitializer());
|
|
2621
2907
|
return initializer && Node7.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
2622
2908
|
}
|
|
2623
|
-
function
|
|
2909
|
+
function readStringArrayProperty4(definition, propertyName) {
|
|
2624
2910
|
const property = definition.getProperty(propertyName);
|
|
2625
2911
|
if (!property || !Node7.isPropertyAssignment(property)) {
|
|
2626
2912
|
return void 0;
|
|
@@ -2634,13 +2920,13 @@ function readStringArrayProperty3(definition, propertyName) {
|
|
|
2634
2920
|
|
|
2635
2921
|
// packages/compiler/src/resources.ts
|
|
2636
2922
|
import { readdir as readdir7 } from "fs/promises";
|
|
2637
|
-
import
|
|
2923
|
+
import path17 from "path";
|
|
2638
2924
|
import {
|
|
2639
2925
|
Node as Node8,
|
|
2640
2926
|
SyntaxKind as SyntaxKind6
|
|
2641
2927
|
} from "ts-morph";
|
|
2642
2928
|
async function analyzeProjectResources(rootDir) {
|
|
2643
|
-
const resourceFiles = await findResourceFiles(
|
|
2929
|
+
const resourceFiles = await findResourceFiles(path17.join(rootDir, "resources"));
|
|
2644
2930
|
if (resourceFiles.length === 0) {
|
|
2645
2931
|
return [];
|
|
2646
2932
|
}
|
|
@@ -2652,7 +2938,7 @@ async function analyzeProjectResources(rootDir) {
|
|
|
2652
2938
|
function analyzeResourceFile(sourceFile, rootDir) {
|
|
2653
2939
|
const definition = findResourceDefinition(sourceFile);
|
|
2654
2940
|
const absoluteFile = sourceFile.getFilePath();
|
|
2655
|
-
const directory =
|
|
2941
|
+
const directory = path17.basename(path17.dirname(absoluteFile));
|
|
2656
2942
|
const defaultUri = `sidecar://resources/${safePathSegment(directory)}`;
|
|
2657
2943
|
const name = getRequiredStringProperty3(definition, "name", sourceFile);
|
|
2658
2944
|
const uri = getOptionalStringProperty3(definition, "uri") ?? defaultUri;
|
|
@@ -2670,7 +2956,7 @@ function analyzeResourceFile(sourceFile, rootDir) {
|
|
|
2670
2956
|
throw new CompilerError(sourceFile, "resource({ ... }) must include a read method.");
|
|
2671
2957
|
}
|
|
2672
2958
|
return {
|
|
2673
|
-
sourceFile:
|
|
2959
|
+
sourceFile: path17.relative(rootDir, absoluteFile),
|
|
2674
2960
|
directory,
|
|
2675
2961
|
uri,
|
|
2676
2962
|
name,
|
|
@@ -2693,7 +2979,7 @@ async function findResourceFiles(resourcesDir) {
|
|
|
2693
2979
|
if (!entry.isDirectory()) {
|
|
2694
2980
|
continue;
|
|
2695
2981
|
}
|
|
2696
|
-
const filePath =
|
|
2982
|
+
const filePath = path17.join(resourcesDir, entry.name, "resource.ts");
|
|
2697
2983
|
if (existsSyncSafe(filePath)) {
|
|
2698
2984
|
files.push(filePath);
|
|
2699
2985
|
}
|
|
@@ -2772,7 +3058,7 @@ function readAnnotations2(definition) {
|
|
|
2772
3058
|
return void 0;
|
|
2773
3059
|
}
|
|
2774
3060
|
const annotations = {};
|
|
2775
|
-
const audience =
|
|
3061
|
+
const audience = readStringArrayProperty5(initializer, "audience")?.filter((value) => value === "user" || value === "assistant");
|
|
2776
3062
|
const priority = getOptionalNumberProperty(initializer, "priority");
|
|
2777
3063
|
const lastModified = getOptionalStringProperty3(initializer, "lastModified");
|
|
2778
3064
|
if (audience?.length) annotations.audience = audience;
|
|
@@ -2801,7 +3087,7 @@ function readIcons2(definition) {
|
|
|
2801
3087
|
return [{
|
|
2802
3088
|
src,
|
|
2803
3089
|
mimeType: getOptionalStringProperty3(object, "mimeType"),
|
|
2804
|
-
sizes:
|
|
3090
|
+
sizes: readStringArrayProperty5(object, "sizes")
|
|
2805
3091
|
}];
|
|
2806
3092
|
});
|
|
2807
3093
|
return icons.length ? icons : void 0;
|
|
@@ -2814,7 +3100,7 @@ function readObjectProperty5(definition, propertyName) {
|
|
|
2814
3100
|
const initializer = unwrapExpression(property.getInitializer());
|
|
2815
3101
|
return initializer && Node8.isObjectLiteralExpression(initializer) ? initializer : void 0;
|
|
2816
3102
|
}
|
|
2817
|
-
function
|
|
3103
|
+
function readStringArrayProperty5(definition, propertyName) {
|
|
2818
3104
|
const property = definition.getProperty(propertyName);
|
|
2819
3105
|
if (!property || !Node8.isPropertyAssignment(property)) {
|
|
2820
3106
|
return void 0;
|
|
@@ -2827,21 +3113,21 @@ function readStringArrayProperty4(definition, propertyName) {
|
|
|
2827
3113
|
}
|
|
2828
3114
|
|
|
2829
3115
|
// packages/compiler/src/server-output.ts
|
|
2830
|
-
import { existsSync as
|
|
3116
|
+
import { existsSync as existsSync6 } from "fs";
|
|
2831
3117
|
import { mkdir as mkdir8, rm, writeFile as writeFile8 } from "fs/promises";
|
|
2832
|
-
import
|
|
3118
|
+
import path18 from "path";
|
|
2833
3119
|
import { build as esbuild2 } from "esbuild";
|
|
2834
3120
|
var SERVER_ENTRYPOINT = "server/index.js";
|
|
2835
3121
|
var VERCEL_FUNCTION_DIR = "functions/api/sidecar.func";
|
|
2836
3122
|
var VERCEL_ENTRYPOINT = `${VERCEL_FUNCTION_DIR}/index.js`;
|
|
2837
3123
|
var VERCEL_HANDLER_FILE = "index.js";
|
|
2838
3124
|
async function buildServerOutput(rootDir, outDir, manifest, identity, host = "node", options = {}) {
|
|
2839
|
-
const cacheDir =
|
|
3125
|
+
const cacheDir = path18.join(rootDir, ".sidecar", "cache", "server");
|
|
2840
3126
|
await mkdir8(cacheDir, { recursive: true });
|
|
2841
|
-
const entryFile =
|
|
3127
|
+
const entryFile = path18.join(cacheDir, "index.ts");
|
|
2842
3128
|
await writeFile8(entryFile, renderServerEntry(rootDir, entryFile, manifest, identity));
|
|
2843
|
-
const serverFile =
|
|
2844
|
-
await mkdir8(
|
|
3129
|
+
const serverFile = path18.join(outDir, SERVER_ENTRYPOINT);
|
|
3130
|
+
await mkdir8(path18.dirname(serverFile), { recursive: true });
|
|
2845
3131
|
await esbuild2({
|
|
2846
3132
|
absWorkingDir: rootDir,
|
|
2847
3133
|
alias: sidecarBundleAliases(rootDir),
|
|
@@ -2855,30 +3141,30 @@ const require = __sidecarCreateRequire(import.meta.url);`
|
|
|
2855
3141
|
legalComments: "none",
|
|
2856
3142
|
minify: false,
|
|
2857
3143
|
nodePaths: [
|
|
2858
|
-
|
|
2859
|
-
|
|
3144
|
+
path18.join(rootDir, "node_modules"),
|
|
3145
|
+
path18.join(process.cwd(), "node_modules")
|
|
2860
3146
|
],
|
|
2861
3147
|
outfile: serverFile,
|
|
2862
3148
|
platform: "node",
|
|
2863
3149
|
sourcemap: false,
|
|
2864
3150
|
target: "node20"
|
|
2865
3151
|
});
|
|
2866
|
-
await writeFile8(
|
|
3152
|
+
await writeFile8(path18.join(outDir, "package.json"), renderServerPackage(identity));
|
|
2867
3153
|
if (host === "vercel") {
|
|
2868
3154
|
const vercelOutputDir = options.vercelOutputDir ?? outDir;
|
|
2869
|
-
await rm(
|
|
2870
|
-
await rm(
|
|
2871
|
-
await writeFile8(
|
|
2872
|
-
await writeFile8(
|
|
3155
|
+
await rm(path18.join(vercelOutputDir, "api"), { recursive: true, force: true });
|
|
3156
|
+
await rm(path18.join(vercelOutputDir, "vercel.json"), { force: true });
|
|
3157
|
+
await writeFile8(path18.join(outDir, VERCEL_HANDLER_FILE), renderVercelEntrypoint());
|
|
3158
|
+
await writeFile8(path18.join(outDir, ".vc-config.json"), renderVercelFunctionConfig());
|
|
2873
3159
|
await mkdir8(vercelOutputDir, { recursive: true });
|
|
2874
|
-
await writeFile8(
|
|
3160
|
+
await writeFile8(path18.join(vercelOutputDir, "config.json"), renderVercelOutputConfig());
|
|
2875
3161
|
} else {
|
|
2876
|
-
await rm(
|
|
2877
|
-
await rm(
|
|
3162
|
+
await rm(path18.join(outDir, "api"), { recursive: true, force: true });
|
|
3163
|
+
await rm(path18.join(outDir, "vercel.json"), { force: true });
|
|
2878
3164
|
}
|
|
2879
3165
|
}
|
|
2880
3166
|
function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
2881
|
-
const entryDir =
|
|
3167
|
+
const entryDir = path18.dirname(entryFile);
|
|
2882
3168
|
const tools = manifest.tools;
|
|
2883
3169
|
const resources = manifest.resources;
|
|
2884
3170
|
const prompts = manifest.prompts;
|
|
@@ -2891,17 +3177,17 @@ function renderServerEntry(rootDir, entryFile, manifest, identity) {
|
|
|
2891
3177
|
`import { isSidecarPrompt, isSidecarResource, isSidecarTool } from "@sidecar-ai/core";`,
|
|
2892
3178
|
`import { isSidecarProxy } from "@sidecar-ai/server/proxy";`,
|
|
2893
3179
|
...tools.map(
|
|
2894
|
-
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3180
|
+
(entry, index) => `import tool${index} from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, entry.sourceFile)))};`
|
|
2895
3181
|
),
|
|
2896
3182
|
...resources.map(
|
|
2897
|
-
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3183
|
+
(entry, index) => `import resource${index} from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, entry.sourceFile)))};`
|
|
2898
3184
|
),
|
|
2899
3185
|
...prompts.map(
|
|
2900
|
-
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir,
|
|
3186
|
+
(entry, index) => `import prompt${index} from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, entry.sourceFile)))};`
|
|
2901
3187
|
),
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
3188
|
+
existsSync6(path18.join(rootDir, "auth.ts")) ? `import authExport from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, "auth.ts")))};` : `const authExport = undefined;`,
|
|
3189
|
+
existsSync6(path18.join(rootDir, "proxy.ts")) ? `import proxyExport from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, "proxy.ts")))};` : `const proxyExport = undefined;`,
|
|
3190
|
+
existsSync6(path18.join(rootDir, "sidecar.config.ts")) ? `import configExport from ${JSON.stringify(toImportSpecifier(entryDir, path18.join(rootDir, "sidecar.config.ts")))};` : `const configExport = undefined;`
|
|
2905
3191
|
].join("\n");
|
|
2906
3192
|
return `${imports}
|
|
2907
3193
|
|
|
@@ -3012,7 +3298,7 @@ function unwrapRuntimeDefault(value) {
|
|
|
3012
3298
|
value &&
|
|
3013
3299
|
typeof value === "object" &&
|
|
3014
3300
|
"default" in value &&
|
|
3015
|
-
Object.keys(value).
|
|
3301
|
+
Object.keys(value).every((key) => key === "default" || key === "__esModule")
|
|
3016
3302
|
) {
|
|
3017
3303
|
return unwrapRuntimeDefault(value.default);
|
|
3018
3304
|
}
|
|
@@ -3104,35 +3390,35 @@ function sidecarBundleAliases(rootDir) {
|
|
|
3104
3390
|
return void 0;
|
|
3105
3391
|
}
|
|
3106
3392
|
return {
|
|
3107
|
-
"sidecar-ai":
|
|
3108
|
-
"@sidecar-ai/auth":
|
|
3109
|
-
"@sidecar-ai/core":
|
|
3110
|
-
"@sidecar-ai/server":
|
|
3111
|
-
"@sidecar-ai/server/proxy":
|
|
3112
|
-
"@sidecar-ai/client":
|
|
3113
|
-
"@sidecar-ai/react":
|
|
3114
|
-
"@sidecar-ai/native":
|
|
3115
|
-
"@sidecar-ai/native/components":
|
|
3116
|
-
"@sidecar-ai/openai":
|
|
3117
|
-
"@sidecar-ai/openai/components":
|
|
3118
|
-
"@sidecar-ai/openai/official":
|
|
3119
|
-
"@sidecar-ai/anthropic":
|
|
3120
|
-
"@sidecar-ai/anthropic/agent":
|
|
3121
|
-
"@sidecar-ai/anthropic/command":
|
|
3122
|
-
"@sidecar-ai/anthropic/components":
|
|
3123
|
-
"@sidecar-ai/anthropic/hooks":
|
|
3124
|
-
"@sidecar-ai/anthropic/mcp":
|
|
3125
|
-
"@sidecar-ai/anthropic/plugin":
|
|
3126
|
-
"@sidecar-ai/anthropic/skill":
|
|
3393
|
+
"sidecar-ai": path18.join(repoRoot, "packages", "sidecar-ai", "src", "index.ts"),
|
|
3394
|
+
"@sidecar-ai/auth": path18.join(repoRoot, "packages", "auth", "src", "index.ts"),
|
|
3395
|
+
"@sidecar-ai/core": path18.join(repoRoot, "packages", "core", "src", "index.ts"),
|
|
3396
|
+
"@sidecar-ai/server": path18.join(repoRoot, "packages", "server", "src", "index.ts"),
|
|
3397
|
+
"@sidecar-ai/server/proxy": path18.join(repoRoot, "packages", "server", "src", "proxy.ts"),
|
|
3398
|
+
"@sidecar-ai/client": path18.join(repoRoot, "packages", "client", "src", "index.ts"),
|
|
3399
|
+
"@sidecar-ai/react": path18.join(repoRoot, "packages", "react", "src", "index.ts"),
|
|
3400
|
+
"@sidecar-ai/native": path18.join(repoRoot, "packages", "native", "src", "index.ts"),
|
|
3401
|
+
"@sidecar-ai/native/components": path18.join(repoRoot, "packages", "native", "src", "components", "index.tsx"),
|
|
3402
|
+
"@sidecar-ai/openai": path18.join(repoRoot, "packages", "openai", "src", "index.ts"),
|
|
3403
|
+
"@sidecar-ai/openai/components": path18.join(repoRoot, "packages", "openai", "src", "components.tsx"),
|
|
3404
|
+
"@sidecar-ai/openai/official": path18.join(repoRoot, "packages", "openai", "src", "official.ts"),
|
|
3405
|
+
"@sidecar-ai/anthropic": path18.join(repoRoot, "packages", "anthropic", "src", "index.ts"),
|
|
3406
|
+
"@sidecar-ai/anthropic/agent": path18.join(repoRoot, "packages", "anthropic", "src", "agent.ts"),
|
|
3407
|
+
"@sidecar-ai/anthropic/command": path18.join(repoRoot, "packages", "anthropic", "src", "command.ts"),
|
|
3408
|
+
"@sidecar-ai/anthropic/components": path18.join(repoRoot, "packages", "anthropic", "src", "components.tsx"),
|
|
3409
|
+
"@sidecar-ai/anthropic/hooks": path18.join(repoRoot, "packages", "anthropic", "src", "hooks.ts"),
|
|
3410
|
+
"@sidecar-ai/anthropic/mcp": path18.join(repoRoot, "packages", "anthropic", "src", "mcp.ts"),
|
|
3411
|
+
"@sidecar-ai/anthropic/plugin": path18.join(repoRoot, "packages", "anthropic", "src", "plugin.ts"),
|
|
3412
|
+
"@sidecar-ai/anthropic/skill": path18.join(repoRoot, "packages", "anthropic", "src", "skill.ts")
|
|
3127
3413
|
};
|
|
3128
3414
|
}
|
|
3129
3415
|
function findSidecarRepoRoot2(startDir) {
|
|
3130
|
-
let current =
|
|
3416
|
+
let current = path18.resolve(startDir);
|
|
3131
3417
|
while (true) {
|
|
3132
|
-
if (
|
|
3418
|
+
if (existsSync6(path18.join(current, "packages", "core", "src", "index.ts"))) {
|
|
3133
3419
|
return current;
|
|
3134
3420
|
}
|
|
3135
|
-
const parent =
|
|
3421
|
+
const parent = path18.dirname(current);
|
|
3136
3422
|
if (parent === current) {
|
|
3137
3423
|
return void 0;
|
|
3138
3424
|
}
|
|
@@ -3142,7 +3428,7 @@ function findSidecarRepoRoot2(startDir) {
|
|
|
3142
3428
|
|
|
3143
3429
|
// packages/compiler/src/build.ts
|
|
3144
3430
|
async function buildProject(options) {
|
|
3145
|
-
const rootDir =
|
|
3431
|
+
const rootDir = path19.resolve(options.rootDir);
|
|
3146
3432
|
const config = analyzeProjectConfig(rootDir);
|
|
3147
3433
|
const target = options.target ?? config.build.target ?? "mcp";
|
|
3148
3434
|
const host = options.host ?? config.build.host ?? "node";
|
|
@@ -3164,7 +3450,7 @@ async function buildProject(options) {
|
|
|
3164
3450
|
}
|
|
3165
3451
|
const outDir = resolveInsideRoot(rootDir, options.outDir ?? config.build.outDir ?? defaultBuildOutDir(host, target));
|
|
3166
3452
|
const runtimeOutDir = resolveRuntimeOutputDir(outDir, host);
|
|
3167
|
-
await buildWidgets(rootDir, runtimeOutDir, tools);
|
|
3453
|
+
await buildWidgets(rootDir, runtimeOutDir, tools, config.build.widgets);
|
|
3168
3454
|
const manifest = {
|
|
3169
3455
|
version: 1,
|
|
3170
3456
|
target,
|
|
@@ -3180,11 +3466,11 @@ async function buildProject(options) {
|
|
|
3180
3466
|
};
|
|
3181
3467
|
await mkdir9(runtimeOutDir, { recursive: true });
|
|
3182
3468
|
await writeFile9(
|
|
3183
|
-
|
|
3469
|
+
path19.join(runtimeOutDir, "manifest.sidecar.json"),
|
|
3184
3470
|
`${JSON.stringify(manifest, null, 2)}
|
|
3185
3471
|
`
|
|
3186
3472
|
);
|
|
3187
|
-
await writeFile9(
|
|
3473
|
+
await writeFile9(path19.join(runtimeOutDir, "README.md"), renderMcpReadme(manifest));
|
|
3188
3474
|
await writeGeneratedTypes(rootDir, tools);
|
|
3189
3475
|
await buildServerOutput(rootDir, runtimeOutDir, manifest, identity, host, {
|
|
3190
3476
|
vercelOutputDir: outDir
|
|
@@ -3202,23 +3488,23 @@ function defaultBuildOutDir(host, target) {
|
|
|
3202
3488
|
}
|
|
3203
3489
|
function resolveRuntimeOutputDir(outDir, host) {
|
|
3204
3490
|
if (host === "vercel") {
|
|
3205
|
-
return
|
|
3491
|
+
return path19.join(outDir, VERCEL_FUNCTION_DIR);
|
|
3206
3492
|
}
|
|
3207
3493
|
return outDir;
|
|
3208
3494
|
}
|
|
3209
3495
|
function resolvePluginOutputBase(rootDir, outDir, host) {
|
|
3210
3496
|
if (host === "vercel" && isVercelBuildOutputDir(outDir)) {
|
|
3211
|
-
return
|
|
3497
|
+
return path19.join(rootDir, "out");
|
|
3212
3498
|
}
|
|
3213
|
-
return
|
|
3499
|
+
return path19.dirname(outDir);
|
|
3214
3500
|
}
|
|
3215
3501
|
function isVercelBuildOutputDir(outDir) {
|
|
3216
|
-
return
|
|
3502
|
+
return path19.basename(outDir) === "output" && path19.basename(path19.dirname(outDir)) === ".vercel";
|
|
3217
3503
|
}
|
|
3218
3504
|
function resolveInsideRoot(rootDir, output) {
|
|
3219
|
-
const resolved =
|
|
3220
|
-
const relative =
|
|
3221
|
-
if (relative.startsWith("..") ||
|
|
3505
|
+
const resolved = path19.resolve(rootDir, output);
|
|
3506
|
+
const relative = path19.relative(rootDir, resolved);
|
|
3507
|
+
if (relative.startsWith("..") || path19.isAbsolute(relative)) {
|
|
3222
3508
|
throw new Error(`Build output must stay inside the project root: ${output}`);
|
|
3223
3509
|
}
|
|
3224
3510
|
return resolved;
|