libretto 0.6.29 → 0.6.30-experimental-runtime-libretto.1

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.
@@ -22,7 +22,6 @@ import {
22
22
  } from "../../shared/workflow/workflow.js";
23
23
  import { normalizeCredentialNames } from "../../shared/workflow/credentials.js";
24
24
  const DEFAULT_RUNTIME_EXTERNALS = [
25
- "libretto",
26
25
  "playwright",
27
26
  "playwright-core",
28
27
  "chromium-bidi"
@@ -408,14 +407,58 @@ function resolveDependencyVersion(sourceDir, packageName, fallbackVersion) {
408
407
  `Unable to determine a version for external package "${packageName}". Add it to your package.json or remove it from --external.`
409
408
  );
410
409
  }
410
+ function resolveLibrettoDependencyVersion(sourceDir, packageName) {
411
+ try {
412
+ const librettoManifestPath = require2.resolve("libretto/package.json", {
413
+ paths: [sourceDir]
414
+ });
415
+ const version2 = readDependencyVersionFromManifest(
416
+ readPackageManifest(librettoManifestPath),
417
+ packageName
418
+ );
419
+ if (version2) {
420
+ return version2;
421
+ }
422
+ } catch {
423
+ }
424
+ const version = readDependencyVersionFromManifest(
425
+ readPackageManifest(join(CURRENT_LIBRETTO_PACKAGE_DIR, "package.json")),
426
+ packageName
427
+ );
428
+ if (version) {
429
+ return version;
430
+ }
431
+ try {
432
+ const manifestPath = require2.resolve(`${packageName}/package.json`, {
433
+ paths: [CURRENT_LIBRETTO_PACKAGE_DIR]
434
+ });
435
+ return readPackageManifest(manifestPath).version ?? null;
436
+ } catch {
437
+ return null;
438
+ }
439
+ }
411
440
  function writeDeployManifest(args) {
441
+ const dependencyPackages = [
442
+ .../* @__PURE__ */ new Set([
443
+ ...BUILT_IN_MANIFEST_DEPENDENCIES,
444
+ ...args.runtimeExternals.filter(
445
+ (packageName) => resolveLibrettoDependencyVersion(args.sourceDir, packageName)
446
+ ),
447
+ ...args.additionalExternals
448
+ ])
449
+ ];
412
450
  const dependencies = Object.fromEntries(
413
- [...BUILT_IN_MANIFEST_DEPENDENCIES, ...args.additionalExternals].map(
414
- (packageName) => [
451
+ dependencyPackages.map((packageName) => {
452
+ const fallbackVersion = packageName === "libretto" ? args.librettoDependency : resolveLibrettoDependencyVersion(args.sourceDir, packageName) ?? void 0;
453
+ return [
415
454
  packageName,
416
- packageName === "libretto" ? args.librettoDependency : resolveDependencyVersion(args.sourceDir, packageName)
417
- ]
418
- )
455
+ packageName === "libretto" ? args.librettoDependency : resolveDependencyVersion(
456
+ args.sourceDir,
457
+ packageName,
458
+ fallbackVersion
459
+ )
460
+ ];
461
+ })
419
462
  );
420
463
  writeFileSync(
421
464
  join(args.outputDir, "package.json"),
@@ -649,7 +692,7 @@ function createBootstrapSource(args) {
649
692
  authProfileRefresh: workflow.authProfileRefresh
650
693
  })});`
651
694
  ).join("\n");
652
- return `import { createRequire } from "node:module";
695
+ return `import { createRequire, Module } from "node:module";
653
696
  import { existsSync, writeFileSync } from "node:fs";
654
697
  import { tmpdir } from "node:os";
655
698
  import { join } from "node:path";
@@ -665,6 +708,45 @@ const BUNDLE_FILENAME = join(
665
708
  const nativeRequire = createRequire(
666
709
  join(tmpdir(), ${JSON.stringify("libretto-deploy-bootstrap.cjs")}),
667
710
  );
711
+ const packageRequire = createRequire(import.meta.url || __filename);
712
+
713
+ function isBarePackageSpecifier(specifier) {
714
+ return (
715
+ !specifier.startsWith(".") &&
716
+ !specifier.startsWith("/") &&
717
+ !specifier.startsWith("node:") &&
718
+ !/^[A-Za-z]:[\\\\/]/.test(specifier)
719
+ );
720
+ }
721
+
722
+ function loadImplementation() {
723
+ const originalRequire = Module.prototype.require;
724
+ function patchedRequire(specifier) {
725
+ try {
726
+ return originalRequire.call(this, specifier);
727
+ } catch (error) {
728
+ if (
729
+ error?.code === "MODULE_NOT_FOUND" &&
730
+ isBarePackageSpecifier(specifier)
731
+ ) {
732
+ Module.prototype.require = originalRequire;
733
+ try {
734
+ return packageRequire(specifier);
735
+ } finally {
736
+ Module.prototype.require = patchedRequire;
737
+ }
738
+ }
739
+ throw error;
740
+ }
741
+ }
742
+ Module.prototype.require = patchedRequire;
743
+
744
+ try {
745
+ return nativeRequire(ensureBundleFile());
746
+ } finally {
747
+ Module.prototype.require = originalRequire;
748
+ }
749
+ }
668
750
 
669
751
  function ensureBundleFile() {
670
752
  if (!existsSync(BUNDLE_FILENAME)) {
@@ -679,7 +761,7 @@ function ensureBundleFile() {
679
761
 
680
762
  function createWorkflowProxy(workflowName, metadata) {
681
763
  const handler = async (ctx, input) => {
682
- const impl = nativeRequire(ensureBundleFile());
764
+ const impl = loadImplementation();
683
765
  const target = getWorkflowFromModuleExports(impl, workflowName);
684
766
  if (!target || typeof target.run !== "function") {
685
767
  throw new Error(
@@ -716,6 +798,11 @@ ${exportLines}
716
798
  async function writeBundledDeployEntrypoint(args) {
717
799
  try {
718
800
  const unresolvedWorkspaceImports = /* @__PURE__ */ new Map();
801
+ const discoveryExternalPackages = /* @__PURE__ */ new Set([
802
+ ...args.externalPackages,
803
+ "libretto"
804
+ ]);
805
+ const unresolvedDiscoveryWorkspaceImports = /* @__PURE__ */ new Map();
719
806
  const implementationBuild = await build({
720
807
  absWorkingDir: args.absSourceDir,
721
808
  bundle: true,
@@ -736,6 +823,25 @@ async function writeBundledDeployEntrypoint(args) {
736
823
  target: "node20",
737
824
  write: false
738
825
  });
826
+ const discoveryBuild = await build({
827
+ absWorkingDir: args.absSourceDir,
828
+ bundle: true,
829
+ entryPoints: [args.absEntryPoint],
830
+ external: [...discoveryExternalPackages],
831
+ format: "cjs",
832
+ outfile: "prebundled-discovery.cjs",
833
+ platform: "node",
834
+ plugins: [
835
+ workspaceSourcePlugin(
836
+ args.workspacePackages,
837
+ discoveryExternalPackages,
838
+ unresolvedDiscoveryWorkspaceImports
839
+ )
840
+ ],
841
+ splitting: false,
842
+ target: "node20",
843
+ write: false
844
+ });
739
845
  const [unresolvedImport] = unresolvedWorkspaceImports;
740
846
  if (unresolvedImport) {
741
847
  const [importPath, packageDir] = unresolvedImport;
@@ -743,6 +849,13 @@ async function writeBundledDeployEntrypoint(args) {
743
849
  `Unable to resolve workspace import "${importPath}" from ${packageDir}.`
744
850
  );
745
851
  }
852
+ const [unresolvedDiscoveryImport] = unresolvedDiscoveryWorkspaceImports;
853
+ if (unresolvedDiscoveryImport) {
854
+ const [importPath, packageDir] = unresolvedDiscoveryImport;
855
+ throw new Error(
856
+ `Unable to resolve workspace import "${importPath}" from ${packageDir}.`
857
+ );
858
+ }
746
859
  const bundledImplementation = implementationBuild.outputFiles?.find(
747
860
  (file) => file.path.endsWith("prebundled.cjs")
748
861
  );
@@ -751,11 +864,17 @@ async function writeBundledDeployEntrypoint(args) {
751
864
  "Bundler did not produce a deployment implementation file."
752
865
  );
753
866
  }
867
+ const bundledDiscovery = discoveryBuild.outputFiles?.find(
868
+ (file) => file.path.endsWith("prebundled-discovery.cjs")
869
+ );
870
+ if (!bundledDiscovery) {
871
+ throw new Error("Bundler did not produce a deployment discovery file.");
872
+ }
754
873
  const workflows = discoverBundledWorkflows({
755
874
  absEntryPoint: args.absEntryPoint,
756
875
  absSourceDir: args.absSourceDir,
757
- bundleBuffer: Buffer.from(bundledImplementation.contents),
758
- externalPackages: args.externalPackages
876
+ bundleBuffer: Buffer.from(bundledDiscovery.contents),
877
+ externalPackages: discoveryExternalPackages
759
878
  });
760
879
  writeFileSync(
761
880
  join(args.outputDir, "index.js"),
@@ -825,6 +944,7 @@ async function createHostedDeployPackage(args) {
825
944
  deploymentName: args.deploymentName,
826
945
  librettoDependency,
827
946
  outputDir,
947
+ runtimeExternals: [...DEFAULT_RUNTIME_EXTERNALS],
828
948
  sourceDir: absSourceDir
829
949
  });
830
950
  writeDeployMetadata({ outputDir, workflows: workflowsWithShareableSource });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libretto",
3
- "version": "0.6.29",
3
+ "version": "0.6.30-experimental-runtime-libretto.1",
4
4
  "description": "AI-powered browser automation library and CLI built on Playwright",
5
5
  "license": "MIT",
6
6
  "homepage": "https://libretto.sh",
@@ -33,6 +33,21 @@
33
33
  "default": "./dist/index.js"
34
34
  }
35
35
  },
36
+ "scripts": {
37
+ "sync:mirrors": "node ../dev-tools/scripts/sync-mirrors.mjs",
38
+ "check:mirrors": "node ../dev-tools/scripts/check-mirrors-sync.mjs",
39
+ "sync-skills": "pnpm run sync:mirrors",
40
+ "check:skills": "pnpm run check:mirrors",
41
+ "build": "tsup --config tsup.config.ts",
42
+ "lint": "lintcn lint --tsconfig tsconfig.json",
43
+ "type-check": "tsc --noEmit",
44
+ "test": "turbo run test:vitest --filter=libretto --log-order=grouped",
45
+ "test:vitest": "vitest run",
46
+ "test:watch": "vitest",
47
+ "cli": "node dist/index.js",
48
+ "generate-changelog": "tsx scripts/generate-changelog.ts",
49
+ "prepack": "pnpm run build"
50
+ },
36
51
  "peerDependencies": {
37
52
  "@ai-sdk/google": "^3.0.51",
38
53
  "@ai-sdk/google-vertex": "^4.0.80"
@@ -65,25 +80,11 @@
65
80
  "dependencies": {
66
81
  "@ai-sdk/anthropic": "^3.0.66",
67
82
  "@ai-sdk/openai": "^3.0.66",
83
+ "affordance": "^0.2.1",
68
84
  "ai": "^6.0.116",
69
85
  "esbuild": "^0.27.0",
70
86
  "playwright": "^1.58.2",
71
87
  "tsx": "^4.21.0",
72
- "zod": "^4.3.6",
73
- "affordance": "^0.2.1"
74
- },
75
- "scripts": {
76
- "sync:mirrors": "node ../dev-tools/scripts/sync-mirrors.mjs",
77
- "check:mirrors": "node ../dev-tools/scripts/check-mirrors-sync.mjs",
78
- "sync-skills": "pnpm run sync:mirrors",
79
- "check:skills": "pnpm run check:mirrors",
80
- "build": "tsup --config tsup.config.ts",
81
- "lint": "lintcn lint --tsconfig tsconfig.json",
82
- "type-check": "tsc --noEmit",
83
- "test": "turbo run test:vitest --filter=libretto --log-order=grouped",
84
- "test:vitest": "vitest run",
85
- "test:watch": "vitest",
86
- "cli": "node dist/index.js",
87
- "generate-changelog": "tsx scripts/generate-changelog.ts"
88
+ "zod": "^4.3.6"
88
89
  }
89
- }
90
+ }
@@ -71,7 +71,6 @@ type BuildHostedDeployTarballArgs = {
71
71
  type CreateHostedDeployPackageArgs = BuildHostedDeployTarballArgs;
72
72
 
73
73
  const DEFAULT_RUNTIME_EXTERNALS = [
74
- "libretto",
75
74
  "playwright",
76
75
  "playwright-core",
77
76
  "chromium-bidi",
@@ -580,22 +579,79 @@ function resolveDependencyVersion(
580
579
  );
581
580
  }
582
581
 
582
+ function resolveLibrettoDependencyVersion(
583
+ sourceDir: string,
584
+ packageName: string,
585
+ ): string | null {
586
+ try {
587
+ const librettoManifestPath = require.resolve("libretto/package.json", {
588
+ paths: [sourceDir],
589
+ });
590
+ const version = readDependencyVersionFromManifest(
591
+ readPackageManifest(librettoManifestPath),
592
+ packageName,
593
+ );
594
+ if (version) {
595
+ return version;
596
+ }
597
+ } catch {
598
+ // Fall through to the current CLI install. Source installs are optional in
599
+ // tests that only exercise manifest construction.
600
+ }
601
+
602
+ const version = readDependencyVersionFromManifest(
603
+ readPackageManifest(join(CURRENT_LIBRETTO_PACKAGE_DIR, "package.json")),
604
+ packageName,
605
+ );
606
+ if (version) {
607
+ return version;
608
+ }
609
+
610
+ try {
611
+ const manifestPath = require.resolve(`${packageName}/package.json`, {
612
+ paths: [CURRENT_LIBRETTO_PACKAGE_DIR],
613
+ });
614
+ return readPackageManifest(manifestPath).version ?? null;
615
+ } catch {
616
+ return null;
617
+ }
618
+ }
619
+
583
620
  function writeDeployManifest(args: {
584
621
  additionalExternals: readonly string[];
585
622
  deploymentName: string;
586
623
  librettoDependency: string;
587
624
  outputDir: string;
625
+ runtimeExternals: readonly string[];
588
626
  sourceDir: string;
589
627
  }): void {
628
+ const dependencyPackages = [
629
+ ...new Set([
630
+ ...BUILT_IN_MANIFEST_DEPENDENCIES,
631
+ ...args.runtimeExternals.filter((packageName) =>
632
+ resolveLibrettoDependencyVersion(args.sourceDir, packageName),
633
+ ),
634
+ ...args.additionalExternals,
635
+ ]),
636
+ ];
590
637
  const dependencies = Object.fromEntries(
591
- [...BUILT_IN_MANIFEST_DEPENDENCIES, ...args.additionalExternals].map(
592
- (packageName) => [
638
+ dependencyPackages.map((packageName) => {
639
+ const fallbackVersion =
640
+ packageName === "libretto"
641
+ ? args.librettoDependency
642
+ : (resolveLibrettoDependencyVersion(args.sourceDir, packageName) ??
643
+ undefined);
644
+ return [
593
645
  packageName,
594
646
  packageName === "libretto"
595
647
  ? args.librettoDependency
596
- : resolveDependencyVersion(args.sourceDir, packageName),
597
- ],
598
- ),
648
+ : resolveDependencyVersion(
649
+ args.sourceDir,
650
+ packageName,
651
+ fallbackVersion,
652
+ ),
653
+ ];
654
+ }),
599
655
  );
600
656
 
601
657
  writeFileSync(
@@ -930,7 +986,7 @@ function createBootstrapSource(args: {
930
986
  // to discover workflow exports. The implementation bundle stays embedded in
931
987
  // the file, while external packages are resolved from node_modules when the
932
988
  // deployed code loads them.
933
- return `import { createRequire } from "node:module";
989
+ return `import { createRequire, Module } from "node:module";
934
990
  import { existsSync, writeFileSync } from "node:fs";
935
991
  import { tmpdir } from "node:os";
936
992
  import { join } from "node:path";
@@ -946,6 +1002,45 @@ const BUNDLE_FILENAME = join(
946
1002
  const nativeRequire = createRequire(
947
1003
  join(tmpdir(), ${JSON.stringify("libretto-deploy-bootstrap.cjs")}),
948
1004
  );
1005
+ const packageRequire = createRequire(import.meta.url || __filename);
1006
+
1007
+ function isBarePackageSpecifier(specifier) {
1008
+ return (
1009
+ !specifier.startsWith(".") &&
1010
+ !specifier.startsWith("/") &&
1011
+ !specifier.startsWith("node:") &&
1012
+ !/^[A-Za-z]:[\\\\/]/.test(specifier)
1013
+ );
1014
+ }
1015
+
1016
+ function loadImplementation() {
1017
+ const originalRequire = Module.prototype.require;
1018
+ function patchedRequire(specifier) {
1019
+ try {
1020
+ return originalRequire.call(this, specifier);
1021
+ } catch (error) {
1022
+ if (
1023
+ error?.code === "MODULE_NOT_FOUND" &&
1024
+ isBarePackageSpecifier(specifier)
1025
+ ) {
1026
+ Module.prototype.require = originalRequire;
1027
+ try {
1028
+ return packageRequire(specifier);
1029
+ } finally {
1030
+ Module.prototype.require = patchedRequire;
1031
+ }
1032
+ }
1033
+ throw error;
1034
+ }
1035
+ }
1036
+ Module.prototype.require = patchedRequire;
1037
+
1038
+ try {
1039
+ return nativeRequire(ensureBundleFile());
1040
+ } finally {
1041
+ Module.prototype.require = originalRequire;
1042
+ }
1043
+ }
949
1044
 
950
1045
  function ensureBundleFile() {
951
1046
  if (!existsSync(BUNDLE_FILENAME)) {
@@ -960,7 +1055,7 @@ function ensureBundleFile() {
960
1055
 
961
1056
  function createWorkflowProxy(workflowName, metadata) {
962
1057
  const handler = async (ctx, input) => {
963
- const impl = nativeRequire(ensureBundleFile());
1058
+ const impl = loadImplementation();
964
1059
  const target = getWorkflowFromModuleExports(impl, workflowName);
965
1060
  if (!target || typeof target.run !== "function") {
966
1061
  throw new Error(
@@ -1008,6 +1103,11 @@ async function writeBundledDeployEntrypoint(args: {
1008
1103
  }> {
1009
1104
  try {
1010
1105
  const unresolvedWorkspaceImports = new Map<string, string>();
1106
+ const discoveryExternalPackages = new Set<string>([
1107
+ ...args.externalPackages,
1108
+ "libretto",
1109
+ ]);
1110
+ const unresolvedDiscoveryWorkspaceImports = new Map<string, string>();
1011
1111
  // The implementation bundle is CommonJS so the bootstrap can load it lazily
1012
1112
  // with createRequire() after workflow discovery, while external packages
1013
1113
  // continue to load through normal Node module resolution.
@@ -1031,6 +1131,27 @@ async function writeBundledDeployEntrypoint(args: {
1031
1131
  target: "node20",
1032
1132
  write: false,
1033
1133
  });
1134
+ // Discovery intentionally keeps libretto external so the local discovery
1135
+ // shim can observe workflow(...) calls without executing the full library.
1136
+ const discoveryBuild = await build({
1137
+ absWorkingDir: args.absSourceDir,
1138
+ bundle: true,
1139
+ entryPoints: [args.absEntryPoint],
1140
+ external: [...discoveryExternalPackages],
1141
+ format: "cjs",
1142
+ outfile: "prebundled-discovery.cjs",
1143
+ platform: "node",
1144
+ plugins: [
1145
+ workspaceSourcePlugin(
1146
+ args.workspacePackages,
1147
+ discoveryExternalPackages,
1148
+ unresolvedDiscoveryWorkspaceImports,
1149
+ ),
1150
+ ],
1151
+ splitting: false,
1152
+ target: "node20",
1153
+ write: false,
1154
+ });
1034
1155
  const [unresolvedImport] = unresolvedWorkspaceImports;
1035
1156
  if (unresolvedImport) {
1036
1157
  const [importPath, packageDir] = unresolvedImport;
@@ -1038,6 +1159,13 @@ async function writeBundledDeployEntrypoint(args: {
1038
1159
  `Unable to resolve workspace import "${importPath}" from ${packageDir}.`,
1039
1160
  );
1040
1161
  }
1162
+ const [unresolvedDiscoveryImport] = unresolvedDiscoveryWorkspaceImports;
1163
+ if (unresolvedDiscoveryImport) {
1164
+ const [importPath, packageDir] = unresolvedDiscoveryImport;
1165
+ throw new Error(
1166
+ `Unable to resolve workspace import "${importPath}" from ${packageDir}.`,
1167
+ );
1168
+ }
1041
1169
 
1042
1170
  const bundledImplementation = implementationBuild.outputFiles?.find(
1043
1171
  (file) => file.path.endsWith("prebundled.cjs"),
@@ -1047,12 +1175,18 @@ async function writeBundledDeployEntrypoint(args: {
1047
1175
  "Bundler did not produce a deployment implementation file.",
1048
1176
  );
1049
1177
  }
1178
+ const bundledDiscovery = discoveryBuild.outputFiles?.find((file) =>
1179
+ file.path.endsWith("prebundled-discovery.cjs"),
1180
+ );
1181
+ if (!bundledDiscovery) {
1182
+ throw new Error("Bundler did not produce a deployment discovery file.");
1183
+ }
1050
1184
 
1051
1185
  const workflows = discoverBundledWorkflows({
1052
1186
  absEntryPoint: args.absEntryPoint,
1053
1187
  absSourceDir: args.absSourceDir,
1054
- bundleBuffer: Buffer.from(bundledImplementation.contents),
1055
- externalPackages: args.externalPackages,
1188
+ bundleBuffer: Buffer.from(bundledDiscovery.contents),
1189
+ externalPackages: discoveryExternalPackages,
1056
1190
  });
1057
1191
 
1058
1192
  writeFileSync(
@@ -1145,6 +1279,7 @@ export async function createHostedDeployPackage(
1145
1279
  deploymentName: args.deploymentName,
1146
1280
  librettoDependency,
1147
1281
  outputDir,
1282
+ runtimeExternals: [...DEFAULT_RUNTIME_EXTERNALS],
1148
1283
  sourceDir: absSourceDir,
1149
1284
  });
1150
1285
  writeDeployMetadata({ outputDir, workflows: workflowsWithShareableSource });