@vite-hub/workflow 0.0.2 → 0.0.3

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.
Files changed (2) hide show
  1. package/dist/vite.js +116 -40
  2. package/package.json +5 -5
package/dist/vite.js CHANGED
@@ -2,8 +2,8 @@ import { t as normalizeWorkflowOptions } from "./config-BDqB6I4E.js";
2
2
  import { r as getCloudflareWorkflowClassName, t as createCloudflareWorkflowBindings } from "./cloudflare-Cds1VIWa.js";
3
3
  import { builtinModules, createRequire } from "node:module";
4
4
  import { cp, mkdir, readFile, readdir, rm, rmdir, stat, symlink, writeFile } from "node:fs/promises";
5
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
6
- import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
7
7
  import { basename as basename$1, dirname as dirname$1, normalize, relative as relative$1, resolve as resolve$1 } from "pathe";
8
8
  import { fileURLToPath } from "node:url";
9
9
  import { build } from "esbuild";
@@ -124,6 +124,7 @@ function deleteOwnedFields(value, ownership) {
124
124
  return next;
125
125
  }
126
126
  function getKeyedArrayEntryValue(value, key) {
127
+ if (key === void 0) return value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string" ? value : void 0;
127
128
  if (!isProviderJsonRecord(value)) return;
128
129
  const entryValue = value[key];
129
130
  return entryValue === null || typeof entryValue === "boolean" || typeof entryValue === "number" || typeof entryValue === "string" ? entryValue : void 0;
@@ -228,6 +229,7 @@ async function writeCloudflareWranglerConfig(options) {
228
229
  //#region ../internal/src/build/vite.ts
229
230
  const projectRootDirectoryMarkers = [
230
231
  ["server", "agents"],
232
+ ["server", "browsers"],
231
233
  ["server", "schedules"],
232
234
  ["server", "templates"],
233
235
  ["server", "workspaces"]
@@ -257,12 +259,12 @@ function includesNitroVitePlugin(value) {
257
259
  if (!value || typeof value !== "object") return false;
258
260
  return "name" in value && value.name === "nitro:main";
259
261
  }
260
- function hasNitroVitePlugin(config) {
261
- return includesNitroVitePlugin(config.plugins);
262
+ function hasNitroConfigContext(config) {
263
+ return config["__vitehubNitroConfigContext"] === true || includesNitroVitePlugin(config.plugins);
262
264
  }
263
265
  function resolveNitroVercelFunctionName(config, product, env = process.env) {
264
266
  const preset = config.nitro?.preset || env.NITRO_PRESET || env.SERVER_PRESET;
265
- const nitro = Boolean(preset) || hasNitroVitePlugin(config);
267
+ const nitro = Boolean(preset) || hasNitroConfigContext(config);
266
268
  const clientOutDir = config.environments?.client?.build?.outDir;
267
269
  const vercel = preset ? preset.startsWith("vercel") : env.VITEHUB_HOSTING === "vercel" || Boolean(env.VERCEL) || Boolean(clientOutDir && /(^|[/\\])\.vercel[/\\]output([/\\]|$)/.test(clientOutDir));
268
270
  return nitro && vercel ? `__${product}.func` : void 0;
@@ -625,6 +627,23 @@ async function writeCloudflareDeploymentOutput(options) {
625
627
  }
626
628
  await Promise.all(writes);
627
629
  }
630
+ async function copyVercelClientOutput(rootDir, clientDir, staticOutputDir) {
631
+ const cloudflareOutputRoot = createDefaultCloudflareOutputRoot(rootDir);
632
+ const outputRelativePath = relative(clientDir, cloudflareOutputRoot);
633
+ const excludesCloudflareOutput = outputRelativePath && outputRelativePath !== ".." && !outputRelativePath.startsWith(`..${sep}`) && !isAbsolute(outputRelativePath);
634
+ await copyClientOutput(clientDir, staticOutputDir);
635
+ if (resolve(clientDir) === resolve(staticOutputDir) || !excludesCloudflareOutput) return;
636
+ try {
637
+ await readFile(resolve(cloudflareOutputRoot, "wrangler.json"));
638
+ } catch (error) {
639
+ if (error.code === "ENOENT") return;
640
+ throw error;
641
+ }
642
+ await rm(resolve(staticOutputDir, outputRelativePath), {
643
+ force: true,
644
+ recursive: true
645
+ });
646
+ }
628
647
  async function writeVercelDeploymentOutput(options) {
629
648
  const { clientDir, staticIndex } = resolveClientOutput(options.rootDir, options.clientOutDir);
630
649
  const outputRoot = options.outputRoot ?? createDefaultVercelOutputRoot(options.rootDir);
@@ -646,7 +665,7 @@ async function writeVercelDeploymentOutput(options) {
646
665
  }),
647
666
  writeFile(resolve(serverDir, ".vc-config.json"), `${stringifyProviderOutputConfig(options.functionConfig ?? createNodeFunctionConfig())}\n`, "utf8"),
648
667
  writeProviderOutputConfig(resolve(outputRoot, "config.json"), config, { keys: options.configKeys }),
649
- staticIndex ? copyClientOutput(clientDir, options.staticOutputDir ?? resolve(outputRoot, "static")) : Promise.resolve()
668
+ staticIndex ? copyVercelClientOutput(options.rootDir, clientDir, options.staticOutputDir ?? resolve(outputRoot, "static")) : Promise.resolve()
650
669
  ]);
651
670
  }
652
671
  async function writeNetlifyDeploymentOutput(options) {
@@ -749,6 +768,60 @@ async function writeProviderDeploymentOutputs(options) {
749
768
  }
750
769
  }
751
770
  //#endregion
771
+ //#region ../internal/src/build/colocated-agent-files.ts
772
+ function formatSize(bytes) {
773
+ const mebibyte = 1024 * 1024;
774
+ return bytes % mebibyte === 0 ? `${bytes / mebibyte} MiB` : `${bytes} bytes`;
775
+ }
776
+ function isFolderAgentEntry(file) {
777
+ if (!/^(?:agent|index)\.(?:c|m)?[jt]s$/i.test(basename(file))) return false;
778
+ return !(basename(file).toLowerCase().startsWith("agent.") && basename(dirname(file)) === "agents" && basename(dirname(dirname(file))) === "server");
779
+ }
780
+ function readColocatedAgentFiles(handler, directoryName, options = {}) {
781
+ if (!isFolderAgentEntry(handler)) return;
782
+ const root = join(dirname(handler), directoryName);
783
+ if (!existsSync(root)) return;
784
+ if (!(options.rejectUnsupportedEntries ? lstatSync(root) : statSync(root)).isDirectory()) {
785
+ if (options.rejectUnsupportedEntries) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} supports regular files and directories only: ${directoryName}`);
786
+ return;
787
+ }
788
+ const files = {};
789
+ let fileCount = 0;
790
+ let totalSize = 0;
791
+ const visit = (directory) => {
792
+ for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
793
+ const file = join(directory, entry.name);
794
+ const target = relative(root, file).replace(/\\/g, "/");
795
+ if (entry.isDirectory()) {
796
+ visit(file);
797
+ continue;
798
+ }
799
+ if (!entry.isFile()) {
800
+ if (options.rejectUnsupportedEntries) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} supports regular files and directories only: ${target}`);
801
+ continue;
802
+ }
803
+ const size = statSync(file).size;
804
+ fileCount += 1;
805
+ if (options.fileCountLimit !== void 0 && fileCount > options.fileCountLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${options.fileCountLimit} files.`);
806
+ if (options.fileSizeLimit !== void 0 && size > options.fileSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent file"} file exceeds ${formatSize(options.fileSizeLimit)}: ${target}`);
807
+ totalSize += size;
808
+ if (options.totalSizeLimit !== void 0 && totalSize > options.totalSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${formatSize(options.totalSizeLimit)}.`);
809
+ const content = readFileSync(file);
810
+ if (content.byteLength !== size) {
811
+ if (options.fileSizeLimit !== void 0 && content.byteLength > options.fileSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent file"} file exceeds ${formatSize(options.fileSizeLimit)}: ${target}`);
812
+ totalSize += content.byteLength - size;
813
+ if (options.totalSizeLimit !== void 0 && totalSize > options.totalSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${formatSize(options.totalSizeLimit)}.`);
814
+ }
815
+ files[target] = {
816
+ content: content.toString("base64"),
817
+ encoding: "base64"
818
+ };
819
+ }
820
+ };
821
+ visit(root);
822
+ return Object.keys(files).length ? files : void 0;
823
+ }
824
+ //#endregion
752
825
  //#region ../internal/src/build/paths.ts
753
826
  function generatedDirSegments(productName) {
754
827
  return [".vitehub", productName];
@@ -1467,7 +1540,7 @@ function discoverFlatServerWorkflowDefinitions(scanDirs, source) {
1467
1540
  function discoverWorkflowDefinitions(options) {
1468
1541
  if (options.mode === "server-workflows") return mergeDefinitions("workflow", discoverFlatServerWorkflowDefinitions(options.scanDirs, "server-workflows"), discoverWorkflowFolders(options.scanDirs, "server-workflows"));
1469
1542
  const roots = resolveDefinitionScanRoots(options.rootDir, options.scanDirs);
1470
- const serverScanDirs = roots.map((root) => resolve$1(root, "server"));
1543
+ const serverScanDirs = options.serverDirs ?? roots.map((root) => resolve$1(root, "server"));
1471
1544
  const folderDefinitions = discoverWorkflowFolders(serverScanDirs, "server-workflows");
1472
1545
  return mergeDefinitions("workflow", discoverDefinitions("workflow", [createSuffixDefinitionSource("vite-suffix", roots, workflowSuffixPattern, normalizeSuffixWorkflowName, { createDefinition: ({ file, name }) => ({
1473
1546
  handler: file,
@@ -1512,7 +1585,6 @@ const WORKFLOW_PRIORITY_NAMES = [
1512
1585
  "server-workflow.js",
1513
1586
  "server-workflow.mjs"
1514
1587
  ];
1515
- const folderAgentEntryPattern = /^(?:agent|index)\.(?:c|m)?[jt]s$/i;
1516
1588
  async function loadVercelWorkflowBuilders() {
1517
1589
  try {
1518
1590
  const require = createRequire(import.meta.url);
@@ -1621,10 +1693,6 @@ async function buildVercelNativeWorkflowOutput(rootDir, definitions, aliases = {
1621
1693
  routes: [...workflowConfig.routes ?? [], ...viteHubConfig.routes ?? []]
1622
1694
  }, null, 2)}\n`, "utf8");
1623
1695
  }
1624
- function isFolderAgentEntry(file) {
1625
- if (!folderAgentEntryPattern.test(basename(file))) return false;
1626
- return !(basename(file).toLowerCase().startsWith("agent.") && basename(dirname(file)) === "agents" && basename(dirname(dirname(file))) === "server");
1627
- }
1628
1696
  function resolveWorkflowUserAppEntry(rootDir) {
1629
1697
  return resolveUserAppEntry(rootDir, { names: getViteMode() === VITEHUB_MODES.workflow ? [...WORKFLOW_PRIORITY_NAMES, ...WORKFLOW_ENTRY_BASE_NAMES] : [...WORKFLOW_ENTRY_BASE_NAMES] });
1630
1698
  }
@@ -1680,29 +1748,31 @@ function readAgentInstructions(file) {
1680
1748
  return existsSync(instructions) && statSync(instructions).isFile() ? resolveInstructionFile(instructions, /* @__PURE__ */ new Set()) : void 0;
1681
1749
  }
1682
1750
  function readAgentSkills(file) {
1683
- if (!isFolderAgentEntry(file)) return void 0;
1684
- const root = dirname(file);
1685
- const skillsRoot = join(root, "skills");
1686
- if (!existsSync(skillsRoot) || !statSync(skillsRoot).isDirectory()) return void 0;
1687
- const sources = {};
1688
- const visit = (directory) => {
1689
- for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
1690
- const target = join(directory, entry.name);
1691
- if (entry.isDirectory()) visit(target);
1692
- else if (entry.isFile()) {
1693
- const workspacePath = relative(root, target).replace(/\\/g, "/");
1694
- sources[`__vitehubAgentSkill:${workspacePath}`] = {
1695
- content: readFileSync(target).toString("base64"),
1696
- encoding: "base64",
1697
- materialize: "build",
1698
- mount: "",
1699
- workspacePath
1700
- };
1701
- }
1702
- }
1703
- };
1704
- visit(skillsRoot);
1705
- return Object.keys(sources).length ? sources : void 0;
1751
+ const files = readColocatedAgentFiles(file, "skills");
1752
+ if (!files) return;
1753
+ return Object.fromEntries(Object.entries(files).map(([path, source]) => {
1754
+ const workspacePath = `skills/${path}`;
1755
+ return [`__vitehubAgentSkill:${workspacePath}`, {
1756
+ ...source,
1757
+ materialize: "build",
1758
+ mount: "",
1759
+ workspacePath
1760
+ }];
1761
+ }));
1762
+ }
1763
+ function readAgentHome(file) {
1764
+ const files = readColocatedAgentFiles(file, "home", {
1765
+ fileCountLimit: 1024,
1766
+ fileSizeLimit: 1024 * 1024,
1767
+ label: "Colocated Agent Home",
1768
+ rejectUnsupportedEntries: true,
1769
+ totalSizeLimit: 4 * 1024 * 1024
1770
+ });
1771
+ if (!files) return;
1772
+ return Object.fromEntries(Object.entries(files).map(([target, source]) => [target, {
1773
+ contents: source.content,
1774
+ encoding: source.encoding
1775
+ }]));
1706
1776
  }
1707
1777
  function renderAgentWorkflowRegistryEntry(registryFile, definition) {
1708
1778
  return [
@@ -1710,7 +1780,7 @@ function renderAgentWorkflowRegistryEntry(registryFile, definition) {
1710
1780
  ` const cached = registryEntryCache.get(${JSON.stringify(definition.name)})`,
1711
1781
  " if (cached) return cached",
1712
1782
  ` const loaded = await ${renderRegistryImport(registryFile, definition.handler)}`,
1713
- ` const agent = agentWithColocatedSkills(workspaceAgentWithSourceRoot("default" in loaded ? loaded.default : loaded, ${JSON.stringify(resolveAgentWorkspaceSourceRoot(definition.handler))}, ${JSON.stringify(readAgentInstructions(definition.handler))}), ${JSON.stringify(readAgentSkills(definition.handler))})`,
1783
+ ` const agent = agentWithColocatedHome(agentWithColocatedSkills(workspaceAgentWithSourceRoot("default" in loaded ? loaded.default : loaded, ${JSON.stringify(resolveAgentWorkspaceSourceRoot(definition.handler))}, ${JSON.stringify(readAgentInstructions(definition.handler))}), ${JSON.stringify(readAgentSkills(definition.handler))}), ${JSON.stringify(readAgentHome(definition.handler))})`,
1714
1784
  ` const entry = { handler: async (context) => await runAgentWorkflowDefinition(agent, { ...context, payload: { ...context.payload, agentIdentity: context.payload?.agentIdentity || { name: ${JSON.stringify(definition.agentIdentity || definition.name)} } } }, runAgentInline) }`,
1715
1785
  ` registryEntryCache.set(${JSON.stringify(definition.name)}, entry)`,
1716
1786
  " return entry",
@@ -1759,7 +1829,7 @@ function createWorkflowRegistryContents(registryFile, definitions, importBases =
1759
1829
  const imports = [
1760
1830
  ...needsAgentRuntime ? [
1761
1831
  `import { runAgentInline } from ${JSON.stringify(agentImportBase)}`,
1762
- `import { agentWithColocatedSkills, runAgentWorkflowDefinition, workspaceAgentWithSourceRoot } from ${JSON.stringify(`${agentImportBase}/runtime/workflow`)}`,
1832
+ `import { agentWithColocatedHome, agentWithColocatedSkills, runAgentWorkflowDefinition, workspaceAgentWithSourceRoot } from ${JSON.stringify(`${agentImportBase}/runtime/workflow`)}`,
1763
1833
  ...installAgentWorkflowRuntime ? [`import { setAgentWorkflowRuntimeLoaders } from ${JSON.stringify(`${agentImportBase}/server/internal`)}`] : []
1764
1834
  ] : [],
1765
1835
  ...needsWorkflowRuntime ? [`import { createWorkflowSteps } from ${JSON.stringify(`${workflowImportBase}/runtime/execute`)}`, `import { takeInlineWorkflowDefinitionForModule } from ${JSON.stringify(`${workflowImportBase}/runtime/state`)}`] : [],
@@ -1848,11 +1918,14 @@ function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowCo
1848
1918
  ""
1849
1919
  ].filter(Boolean).join("\n");
1850
1920
  }
1851
- async function writeProviderEntries(rootDir, workflow, importBases = {}) {
1921
+ async function writeProviderEntries(rootDir, workflow, importBases = {}, serverDirs) {
1852
1922
  const generatedDir = ensureGeneratedDir(rootDir, productName);
1853
1923
  await mkdir(generatedDir, { recursive: true });
1854
1924
  const registryFile = resolve(generatedDir, generatedRegistryFileName);
1855
- const definitions = discoverWorkflowDefinitions({ rootDir });
1925
+ const definitions = discoverWorkflowDefinitions({
1926
+ rootDir,
1927
+ serverDirs
1928
+ });
1856
1929
  const providerDefinitions = definitions;
1857
1930
  const userAppEntry = resolveWorkflowUserAppEntry(rootDir);
1858
1931
  const cloudflareWorkflowConfig = resolveWorkflowConfig(workflow, "cloudflare");
@@ -1969,7 +2042,7 @@ async function generateProviderOutputs(options) {
1969
2042
  workflow: options.importBase,
1970
2043
  workspace: options.workspaceImportBase,
1971
2044
  workspaceDependencies: options.workspaceDependencyRuntimeImports
1972
- });
2045
+ }, options.serverDirs);
1973
2046
  const cloudflareWorkflowConfig = resolveWorkflowConfig(options.workflow, "cloudflare");
1974
2047
  const vercelWorkflowConfig = resolveWorkflowConfig(options.workflow, "vercel");
1975
2048
  const cloudflareOutput = cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare" ? createCloudflareOutput(options.rootDir, artifacts, options.providerImportAliases) : void 0;
@@ -2001,10 +2074,12 @@ function hubWorkflow(options) {
2001
2074
  const internalOptions = options;
2002
2075
  let resolved;
2003
2076
  let workflow = options;
2077
+ let serverDirs;
2004
2078
  return {
2005
2079
  name: "@vite-hub/workflow/vite",
2006
2080
  config(config) {
2007
2081
  workflow = config.workflow ?? workflow;
2082
+ serverDirs = config["__vitehubServerDirs"] ?? serverDirs;
2008
2083
  },
2009
2084
  configResolved(config) {
2010
2085
  resolved = config;
@@ -2025,6 +2100,7 @@ function hubWorkflow(options) {
2025
2100
  ...internalOptions?.providerImportAliases
2026
2101
  },
2027
2102
  rootDir: resolved.root,
2103
+ serverDirs,
2028
2104
  serverFunctionName: resolveNitroVercelFunctionName(resolved, "workflow"),
2029
2105
  workflow,
2030
2106
  workspaceDependencyRuntimeImports: internalOptions?.workspaceDependencyRuntimeImports,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vite-hub/workflow",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Workflow primitives and Vite integration for ViteHub.",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,7 +46,7 @@
46
46
  "esbuild": "^0.28.1",
47
47
  "h3": "2.0.1-rc.25",
48
48
  "pathe": "^2.0.3",
49
- "@vite-hub/runtime": "0.0.2"
49
+ "@vite-hub/runtime": "0.0.3"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^24.13.3",
@@ -59,11 +59,11 @@
59
59
  "@vite-hub/internal": "0.0.1"
60
60
  },
61
61
  "peerDependencies": {
62
- "@workflow/builders": "4.0.5",
62
+ "@workflow/builders": "5.0.0-beta.35",
63
63
  "openworkflow": "^0.9.0",
64
64
  "vite": ">=8.0.0",
65
- "workflow": "^4.6.0",
66
- "@vite-hub/database": "0.0.2"
65
+ "workflow": "5.0.0-beta.35",
66
+ "@vite-hub/database": "0.0.3"
67
67
  },
68
68
  "peerDependenciesMeta": {
69
69
  "@vite-hub/database": {