flowdular 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1861,7 +1861,7 @@ var EXPRESSIONS = new Map(
1861
1861
  );
1862
1862
 
1863
1863
  // ../contracts/src/index.ts
1864
- var PLATFORM_API_VERSION = "0.2.3";
1864
+ var PLATFORM_API_VERSION = "0.2.4";
1865
1865
 
1866
1866
  // src/module-templates.ts
1867
1867
  function packageSuffix(id) {
@@ -4394,6 +4394,14 @@ import * as nodeCrypto2 from "node:crypto";
4394
4394
  import * as nodeCrypto from "node:crypto";
4395
4395
  var KEYRING_KEY_BYTES = 32;
4396
4396
  var KEYRING_MAX_PREVIOUS_KEYS = 8;
4397
+ var KeyringError = class extends Error {
4398
+ code;
4399
+ constructor(code, message, options) {
4400
+ super(message, options);
4401
+ this.name = "KeyringError";
4402
+ this.code = code;
4403
+ }
4404
+ };
4397
4405
  function keyFingerprint(key) {
4398
4406
  return nodeCrypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
4399
4407
  }
@@ -4842,17 +4850,27 @@ function createModuleRegistry(input) {
4842
4850
  });
4843
4851
  }
4844
4852
 
4853
+ // ../kernel/src/variable-registry.ts
4854
+ var VariableResolutionError = class extends Error {
4855
+ constructor(code, message) {
4856
+ super(message);
4857
+ this.code = code;
4858
+ this.name = "VariableResolutionError";
4859
+ }
4860
+ code;
4861
+ };
4862
+
4845
4863
  // src/module-install.ts
4846
4864
  import {
4847
- lstat as lstat2,
4865
+ lstat,
4848
4866
  mkdir,
4849
- readFile as readFile6,
4867
+ readFile as readFile4,
4850
4868
  readdir as readdir3,
4851
4869
  rename,
4852
4870
  rm,
4853
4871
  writeFile
4854
4872
  } from "node:fs/promises";
4855
- import { dirname as dirname5, join as join5, relative as relative5 } from "node:path";
4873
+ import { dirname as dirname5, join as join4, relative as relative5 } from "node:path";
4856
4874
 
4857
4875
  // src/module-artifact.ts
4858
4876
  import { parse as parseYaml2 } from "yaml";
@@ -5010,167 +5028,156 @@ function validateModuleArtifact(value) {
5010
5028
  return artifact;
5011
5029
  }
5012
5030
 
5013
- // src/sdk.ts
5031
+ // ../kernel/src/module-manifests.ts
5032
+ import { lstatSync, readdirSync, readFileSync, realpathSync } from "node:fs";
5014
5033
  import { createRequire } from "node:module";
5015
- import { readFile as readFile3 } from "node:fs/promises";
5016
- import { dirname as dirname3, join as join2 } from "node:path";
5017
- var SDK_VERSION = "0.6.0";
5018
- var LIBRARIES = /* @__PURE__ */ new Set([
5019
- "ai-provider",
5020
- "cli-protocol",
5021
- "client",
5022
- "contracts",
5023
- "database",
5024
- "database-pglite",
5025
- "database-testing",
5026
- "dev-console",
5027
- "harness",
5028
- "kernel",
5029
- "server",
5030
- "storage",
5031
- "ui"
5034
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join2, relative as relative3, resolve as resolve2 } from "node:path";
5035
+ var SDK_INDEX = "@flowdular/sdk/modules.json";
5036
+ var SDK_IMPORT = /^@flowdular\/sdk\/modules\/[a-z0-9-]+$/;
5037
+ var SDK_INDEX_LIMIT = 256;
5038
+ var UNRESOLVED = /* @__PURE__ */ new Set([
5039
+ "MODULE_NOT_FOUND",
5040
+ "ERR_PACKAGE_PATH_NOT_EXPORTED"
5032
5041
  ]);
5033
- var CORE_MODULES = /* @__PURE__ */ new Set([
5034
- "agents",
5035
- "auth",
5036
- "automations",
5037
- "profile",
5038
- "sandbox",
5039
- "system",
5040
- "users",
5041
- "workflows"
5042
+ var SKIPPED_DIRECTORIES2 = /* @__PURE__ */ new Set([
5043
+ ".git",
5044
+ ".flowdular",
5045
+ ".vercel",
5046
+ "node_modules",
5047
+ "dist"
5042
5048
  ]);
5043
- function sdkSpecifier(name) {
5044
- const suffix = name.slice("@flowdular/".length);
5045
- if (!name.startsWith("@flowdular/")) return name;
5046
- if (LIBRARIES.has(suffix)) return `@flowdular/sdk/${suffix}`;
5047
- if (suffix.startsWith("module-") && CORE_MODULES.has(suffix.slice(7)))
5048
- return `@flowdular/sdk/modules/${suffix.slice(7)}`;
5049
- return name;
5049
+ function errorCode(error) {
5050
+ return error.code ?? "";
5050
5051
  }
5051
- function sdkSource(source) {
5052
- return source.replace(/@flowdular\/[a-z0-9-]+/g, sdkSpecifier);
5052
+ function insideRealPath(root, path, shown = path) {
5053
+ const canonicalRoot = realpathSync(root);
5054
+ const canonical2 = realpathSync(path);
5055
+ const fromRoot = relative3(canonicalRoot, canonical2);
5056
+ if (fromRoot.startsWith("..") || isAbsolute2(fromRoot)) {
5057
+ throw new Error(`Path escapes the workspace through a link: ${shown}`);
5058
+ }
5059
+ return canonical2;
5053
5060
  }
5054
- function npmPackage(specifier) {
5055
- return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
5061
+ function manifestPackage(path) {
5062
+ try {
5063
+ const manifest2 = JSON.parse(readFileSync(path, "utf8"));
5064
+ return typeof manifest2.package === "string" ? manifest2.package : void 0;
5065
+ } catch {
5066
+ return void 0;
5067
+ }
5056
5068
  }
5057
- async function sdkModules(workspace) {
5058
- const require2 = createRequire(join2(workspace.root, "platform/package.json"));
5069
+ function moduleRootDirectories(workspaceRoot, roots2) {
5070
+ const configured = roots2 ?? ["modules"];
5071
+ if (!Array.isArray(configured) || configured.length === 0 || configured.some(
5072
+ (root) => typeof root !== "string" || !root || root.startsWith(".") || root.includes("\\") || root.split("/").some((part) => part === ".." || !part)
5073
+ )) {
5074
+ throw new Error(
5075
+ "Invalid modules.roots. Use relative workspace directories."
5076
+ );
5077
+ }
5078
+ return configured.map((root) => {
5079
+ const path = resolve2(workspaceRoot, root);
5080
+ if (!relative3(workspaceRoot, path)) {
5081
+ throw new Error("The workspace root cannot be a module root.");
5082
+ }
5083
+ return path;
5084
+ });
5085
+ }
5086
+ function sdkModuleManifests(workspaceRoot) {
5087
+ const require2 = createRequire(join2(workspaceRoot, "platform/package.json"));
5059
5088
  let indexPath;
5060
5089
  try {
5061
- indexPath = require2.resolve("@flowdular/sdk/modules.json");
5090
+ indexPath = require2.resolve(SDK_INDEX);
5062
5091
  } catch (error) {
5063
- if (["MODULE_NOT_FOUND", "ERR_PACKAGE_PATH_NOT_EXPORTED"].includes(
5064
- error.code ?? ""
5065
- ))
5066
- return /* @__PURE__ */ new Map();
5092
+ if (UNRESOLVED.has(errorCode(error))) return /* @__PURE__ */ new Map();
5067
5093
  throw error;
5068
5094
  }
5069
- const index = JSON.parse(await readFile3(indexPath, "utf8"));
5070
- if (index.schemaVersion !== 1 || !Array.isArray(index.modules) || index.modules.length > 256)
5095
+ const index = JSON.parse(readFileSync(indexPath, "utf8"));
5096
+ if (index.schemaVersion !== 1 || !Array.isArray(index.modules) || index.modules.length > SDK_INDEX_LIMIT) {
5071
5097
  throw new Error("Invalid SDK module index.");
5098
+ }
5099
+ const sdkRoot = dirname3(indexPath);
5072
5100
  const result2 = /* @__PURE__ */ new Map();
5073
5101
  for (const entry of index.modules) {
5074
- if (!/^@flowdular\/sdk\/modules\/[a-z0-9-]+$/.test(entry.import))
5102
+ if (typeof entry?.import !== "string" || !SDK_IMPORT.test(entry.import)) {
5075
5103
  throw new Error("Invalid SDK module entrypoint.");
5076
- const path = await resolveExistingInside(
5077
- dirname3(indexPath),
5078
- entry.manifest
5079
- );
5104
+ }
5105
+ if (typeof entry.manifest !== "string") {
5106
+ throw new Error("Invalid SDK module manifest path.");
5107
+ }
5108
+ const lexical = resolve2(sdkRoot, entry.manifest);
5109
+ const fromRoot = relative3(sdkRoot, lexical);
5110
+ if (fromRoot.startsWith("..") || isAbsolute2(fromRoot)) {
5111
+ throw new Error(`Path escapes the workspace: ${entry.manifest}`);
5112
+ }
5113
+ const path = insideRealPath(sdkRoot, lexical, entry.manifest);
5080
5114
  if (result2.has(path)) throw new Error("Duplicate SDK module path.");
5081
5115
  result2.set(path, entry.import);
5082
5116
  }
5083
5117
  return result2;
5084
5118
  }
5085
- function sdkScaffold(files) {
5086
- return new Map(
5087
- [...files].map(([path, source]) => {
5088
- if (path === "spec/module.yaml" || path === "module.json")
5089
- return [path, source];
5090
- if (path !== "package.json") return [path, sdkSource(source)];
5091
- const pkg = JSON.parse(source);
5092
- for (const section of [pkg.dependencies, pkg.devDependencies])
5093
- if (section) {
5094
- for (const name of Object.keys(section))
5095
- if (sdkSpecifier(name) !== name) delete section[name];
5096
- }
5097
- pkg.dependencies ??= {};
5098
- pkg.dependencies["@flowdular/sdk"] = SDK_VERSION;
5099
- return [path, JSON.stringify(pkg, null, " ") + "\n"];
5100
- })
5101
- );
5102
- }
5103
-
5104
- // src/module-files.ts
5105
- import { createRequire as createRequire2 } from "node:module";
5106
- import { lstat, readFile as readFile4 } from "node:fs/promises";
5107
- import { join as join3, relative as relative3 } from "node:path";
5108
- function moduleRoots(workspace) {
5109
- const roots2 = workspace.config.modules?.roots ?? ["modules"];
5110
- if (!Array.isArray(roots2) || !roots2.length || roots2.some(
5111
- (root) => typeof root !== "string" || !root || root.startsWith(".") || root.includes("\\") || root.split("/").some((part) => part === ".." || !part)
5112
- ))
5113
- throw new Error(
5114
- "Invalid modules.roots. Use relative workspace directories."
5115
- );
5116
- return roots2.map((root) => {
5117
- const path = resolveInside(workspace.root, root);
5118
- if (!relative3(workspace.root, path))
5119
- throw new Error("The workspace root cannot be a module root.");
5120
- return path;
5121
- });
5122
- }
5123
- async function findModuleFiles(workspace) {
5119
+ function findModuleManifests(workspaceRoot, roots2) {
5124
5120
  const files = /* @__PURE__ */ new Set();
5125
- for (const root of moduleRoots(workspace)) {
5121
+ for (const root of moduleRootDirectories(workspaceRoot, roots2)) {
5126
5122
  try {
5127
- await lstat(root);
5123
+ lstatSync(root);
5128
5124
  } catch (error) {
5129
- if (error.code === "ENOENT") continue;
5125
+ if (errorCode(error) === "ENOENT") continue;
5130
5126
  throw error;
5131
5127
  }
5132
- await resolveExistingInside(workspace.root, root);
5133
- for (const file of await findNamedFiles(root, "module.json")) {
5134
- if (relative3(root, file).split("/").length === 2) files.add(file);
5128
+ insideRealPath(workspaceRoot, root);
5129
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
5130
+ if (!entry.isDirectory() || SKIPPED_DIRECTORIES2.has(entry.name)) continue;
5131
+ const path = join2(root, entry.name, "module.json");
5132
+ try {
5133
+ if (!lstatSync(path).isDirectory()) files.add(path);
5134
+ } catch (error) {
5135
+ if (errorCode(error) !== "ENOENT") throw error;
5136
+ }
5135
5137
  }
5136
5138
  }
5137
5139
  const packages = /* @__PURE__ */ new Set();
5138
- for (const file of files)
5139
- packages.add(
5140
- JSON.parse(await readFile4(file, "utf8")).package
5141
- );
5142
- for (const file of (await sdkModules(workspace)).keys()) {
5143
- const manifest2 = JSON.parse(await readFile4(file, "utf8"));
5144
- if (!packages.has(manifest2.package)) files.add(file);
5140
+ for (const file of files) {
5141
+ const name = manifestPackage(file);
5142
+ if (name) packages.add(name);
5143
+ }
5144
+ for (const file of sdkModuleManifests(workspaceRoot).keys()) {
5145
+ const name = manifestPackage(file);
5146
+ if (!name || !packages.has(name)) files.add(file);
5145
5147
  }
5146
- const platformPackage = join3(workspace.root, "platform/package.json");
5148
+ const platformPackage = join2(workspaceRoot, "platform/package.json");
5149
+ let dependencies = {};
5147
5150
  try {
5148
- const pkg = JSON.parse(await readFile4(platformPackage, "utf8"));
5149
- const require2 = createRequire2(platformPackage);
5150
- for (const name of Object.keys(pkg.dependencies ?? {}).sort()) {
5151
- if (!name.startsWith("@flowdular/module-") || packages.has(name))
5152
- continue;
5153
- let file;
5154
- try {
5155
- file = require2.resolve(name + "/module.json");
5156
- } catch (error) {
5157
- if (["MODULE_NOT_FOUND", "ERR_PACKAGE_PATH_NOT_EXPORTED"].includes(
5158
- error.code ?? ""
5159
- ))
5160
- continue;
5161
- throw error;
5162
- }
5163
- files.add(file);
5164
- }
5151
+ dependencies = JSON.parse(readFileSync(platformPackage, "utf8")).dependencies ?? {};
5165
5152
  } catch (error) {
5166
- if (error.code !== "ENOENT") throw error;
5153
+ if (errorCode(error) !== "ENOENT") throw error;
5154
+ }
5155
+ const require2 = createRequire(platformPackage);
5156
+ for (const name of Object.keys(dependencies).sort()) {
5157
+ if (!name.startsWith("@flowdular/module-") || packages.has(name)) continue;
5158
+ try {
5159
+ files.add(require2.resolve(`${name}/module.json`));
5160
+ } catch (error) {
5161
+ if (!UNRESOLVED.has(errorCode(error))) throw error;
5162
+ }
5167
5163
  }
5168
5164
  return [...files].sort();
5169
5165
  }
5170
5166
 
5167
+ // src/module-files.ts
5168
+ function configuredRoots(workspace) {
5169
+ return workspace.config.modules?.roots;
5170
+ }
5171
+ function moduleRoots(workspace) {
5172
+ return [...moduleRootDirectories(workspace.root, configuredRoots(workspace))];
5173
+ }
5174
+ async function findModuleFiles(workspace) {
5175
+ return [...findModuleManifests(workspace.root, configuredRoots(workspace))];
5176
+ }
5177
+
5171
5178
  // src/module-validate.ts
5172
- import { access as access2, readFile as readFile5, readdir as readdir2 } from "node:fs/promises";
5173
- import { dirname as dirname4, join as join4, relative as relative4 } from "node:path";
5179
+ import { access as access2, readFile as readFile3, readdir as readdir2 } from "node:fs/promises";
5180
+ import { dirname as dirname4, join as join3, relative as relative4 } from "node:path";
5174
5181
  import { parse as parseYaml3 } from "yaml";
5175
5182
 
5176
5183
  // ../cli-protocol/src/index.ts
@@ -5887,8 +5894,8 @@ function migrationIdentifierIssues(sql) {
5887
5894
  }
5888
5895
 
5889
5896
  // ../kernel/src/runtime-config.ts
5890
- import { lstatSync } from "node:fs";
5891
- import { resolve as resolve2 } from "node:path";
5897
+ import { lstatSync as lstatSync2 } from "node:fs";
5898
+ import { resolve as resolve3 } from "node:path";
5892
5899
  var UnsafeLocalStatePathError = class extends Error {
5893
5900
  code = "UNSAFE_LOCAL_STATE_PATH";
5894
5901
  constructor(path, expected) {
@@ -5897,9 +5904,9 @@ var UnsafeLocalStatePathError = class extends Error {
5897
5904
  }
5898
5905
  };
5899
5906
  function flowdularStateDirectory(workspaceRoot) {
5900
- const directory = resolve2(workspaceRoot, ".flowdular");
5907
+ const directory = resolve3(workspaceRoot, ".flowdular");
5901
5908
  try {
5902
- const info = lstatSync(directory);
5909
+ const info = lstatSync2(directory);
5903
5910
  if (info.isSymbolicLink() || !info.isDirectory()) {
5904
5911
  throw new UnsafeLocalStatePathError(directory, "directory");
5905
5912
  }
@@ -5910,8 +5917,8 @@ function flowdularStateDirectory(workspaceRoot) {
5910
5917
  }
5911
5918
 
5912
5919
  // ../database/src/provider.ts
5913
- import { readFileSync } from "node:fs";
5914
- import { resolve as resolve3 } from "node:path";
5920
+ import { readFileSync as readFileSync2 } from "node:fs";
5921
+ import { resolve as resolve4 } from "node:path";
5915
5922
 
5916
5923
  // ../database/src/postgresql.ts
5917
5924
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -6409,7 +6416,7 @@ function postgresTlsAuthority(environment) {
6409
6416
  if (!path) return inline || void 0;
6410
6417
  let contents;
6411
6418
  try {
6412
- contents = readFileSync(path, "utf8");
6419
+ contents = readFileSync2(path, "utf8");
6413
6420
  } catch (error) {
6414
6421
  throw new Error(
6415
6422
  `FD_DATABASE_TLS_CA_FILE could not be read: ${error instanceof Error ? error.message : String(error)}`
@@ -6433,7 +6440,7 @@ function databaseProviderConfigFromEnvironment(environment = process.env, worksp
6433
6440
  workspaceRoot,
6434
6441
  environment,
6435
6442
  pglite: {
6436
- dataDirectory: environment.NODE_ENV === "test" ? void 0 : configured ?? resolve3(
6443
+ dataDirectory: environment.NODE_ENV === "test" ? void 0 : configured ?? resolve4(
6437
6444
  flowdularStateDirectory(workspaceRoot),
6438
6445
  "data",
6439
6446
  "pglite"
@@ -6546,11 +6553,28 @@ function databaseProviderConfigFromEnvironment(environment = process.env, worksp
6546
6553
  }
6547
6554
  };
6548
6555
  }
6556
+ function reportIdleConnectionError(error) {
6557
+ const code = error.code;
6558
+ console.warn(
6559
+ `An idle pooled PostgreSQL connection failed (${typeof code === "string" ? `${code}: ` : ""}${error.message}). The pool discards it and the next query opens a new one.`
6560
+ );
6561
+ }
6562
+ function ignoreLeasedClientError() {
6563
+ }
6549
6564
  function postgresDriverPool(pool) {
6565
+ const guardedClients = /* @__PURE__ */ new WeakSet();
6566
+ const guard = (client) => {
6567
+ if (!client.on || guardedClients.has(client)) return;
6568
+ guardedClients.add(client);
6569
+ client.on("error", ignoreLeasedClientError);
6570
+ };
6571
+ pool.on?.("error", reportIdleConnectionError);
6572
+ pool.on?.("connect", guard);
6550
6573
  return {
6551
6574
  cancellation: "before-start",
6552
6575
  async connect() {
6553
6576
  const client = await pool.connect();
6577
+ guard(client);
6554
6578
  return {
6555
6579
  async query({ text, values: values2 }) {
6556
6580
  const result2 = await client.query({
@@ -7038,15 +7062,15 @@ async function exists(path) {
7038
7062
  }
7039
7063
  }
7040
7064
  async function readJson(path) {
7041
- return JSON.parse(await readFile5(path, "utf8"));
7065
+ return JSON.parse(await readFile3(path, "utf8"));
7042
7066
  }
7043
7067
  async function clientSourceFiles(moduleRoot) {
7044
- const clientRoot = join4(moduleRoot, "src/client");
7068
+ const clientRoot = join3(moduleRoot, "src/client");
7045
7069
  if (!await exists(clientRoot)) return [];
7046
7070
  return (await readdir2(clientRoot, {
7047
7071
  recursive: true,
7048
7072
  withFileTypes: true
7049
- })).filter((entry) => entry.isFile() && /\.(?:ts|tsx|tsrx)$/.test(entry.name)).map((entry) => join4(entry.parentPath, entry.name));
7073
+ })).filter((entry) => entry.isFile() && /\.(?:ts|tsx|tsrx)$/.test(entry.name)).map((entry) => join3(entry.parentPath, entry.name));
7050
7074
  }
7051
7075
  async function platformIssues(moduleRoot, manifest2) {
7052
7076
  const issues = [];
@@ -7054,7 +7078,7 @@ async function platformIssues(moduleRoot, manifest2) {
7054
7078
  let packageName;
7055
7079
  let packageVersion;
7056
7080
  try {
7057
- const pkg = await readJson(join4(moduleRoot, "package.json"));
7081
+ const pkg = await readJson(join3(moduleRoot, "package.json"));
7058
7082
  exports = pkg.exports ?? {};
7059
7083
  packageName = pkg.name;
7060
7084
  packageVersion = pkg.version;
@@ -7096,7 +7120,7 @@ async function platformIssues(moduleRoot, manifest2) {
7096
7120
  );
7097
7121
  }
7098
7122
  if (manifest2.platform?.server === true) {
7099
- if (!await exists(join4(moduleRoot, "src/platform.ts"))) {
7123
+ if (!await exists(join3(moduleRoot, "src/platform.ts"))) {
7100
7124
  issues.push(
7101
7125
  issue(
7102
7126
  "PLATFORM_SERVER_ENTRY_MISSING",
@@ -7116,7 +7140,7 @@ async function platformIssues(moduleRoot, manifest2) {
7116
7140
  }
7117
7141
  }
7118
7142
  if (manifest2.platform?.client === true) {
7119
- if (!await exists(join4(moduleRoot, "src/client/index.ts"))) {
7143
+ if (!await exists(join3(moduleRoot, "src/client/index.ts"))) {
7120
7144
  issues.push(
7121
7145
  issue(
7122
7146
  "PLATFORM_CLIENT_ENTRY_MISSING",
@@ -7138,11 +7162,11 @@ async function platformIssues(moduleRoot, manifest2) {
7138
7162
  return issues;
7139
7163
  }
7140
7164
  async function specIssues(moduleRoot, manifest2, specDirectory2) {
7141
- const specPath = join4(specDirectory2, "module.yaml");
7165
+ const specPath = join3(specDirectory2, "module.yaml");
7142
7166
  let spec;
7143
7167
  try {
7144
7168
  spec = parseYaml3(
7145
- await readFile5(join4(moduleRoot, specPath), "utf8")
7169
+ await readFile3(join3(moduleRoot, specPath), "utf8")
7146
7170
  );
7147
7171
  } catch (error) {
7148
7172
  return [
@@ -7217,7 +7241,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
7217
7241
  const referenceBundleKeys = /* @__PURE__ */ new Set();
7218
7242
  for (const locale of manifest2.locales) {
7219
7243
  const path = `translations/${locale}.json`;
7220
- if (!await exists(join4(moduleRoot, path))) {
7244
+ if (!await exists(join3(moduleRoot, path))) {
7221
7245
  issues.push(
7222
7246
  issue(
7223
7247
  "TRANSLATION_FILE_MISSING",
@@ -7228,7 +7252,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
7228
7252
  continue;
7229
7253
  }
7230
7254
  try {
7231
- const bundle = await readJson(join4(moduleRoot, path));
7255
+ const bundle = await readJson(join3(moduleRoot, path));
7232
7256
  if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
7233
7257
  throw new Error("Expected a JSON object.");
7234
7258
  }
@@ -7283,7 +7307,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
7283
7307
  const missing = /* @__PURE__ */ new Map();
7284
7308
  const pattern = /\bt\s*\(\s*(['"])([a-zA-Z0-9._-]+)\1/g;
7285
7309
  for (const file of files) {
7286
- const source = await readFile5(file, "utf8");
7310
+ const source = await readFile3(file, "utf8");
7287
7311
  for (const match of source.matchAll(pattern)) {
7288
7312
  const fullKey = match[2];
7289
7313
  if (!fullKey.startsWith(prefix) || fullKey.endsWith(".")) continue;
@@ -7325,7 +7349,7 @@ function filtersTags(source) {
7325
7349
  async function userInterfaceIssues(moduleRoot) {
7326
7350
  const issues = [];
7327
7351
  for (const file of await clientSourceFiles(moduleRoot)) {
7328
- const source = await readFile5(file, "utf8");
7352
+ const source = await readFile3(file, "utf8");
7329
7353
  const path = relative4(moduleRoot, file);
7330
7354
  if (/<table\b/.test(source)) {
7331
7355
  issues.push(
@@ -7370,11 +7394,11 @@ async function userInterfaceIssues(moduleRoot) {
7370
7394
  return issues;
7371
7395
  }
7372
7396
  async function migrationIssues(moduleRoot) {
7373
- const directory = join4(moduleRoot, "migrations");
7397
+ const directory = join3(moduleRoot, "migrations");
7374
7398
  if (!await exists(directory)) return [];
7375
7399
  const issues = [];
7376
7400
  for (const name of (await readdir2(directory)).filter((entry) => entry.endsWith(".up.sql")).sort()) {
7377
- const sql = await readFile5(join4(directory, name), "utf8");
7401
+ const sql = await readFile3(join3(directory, name), "utf8");
7378
7402
  for (const found of migrationIdentifierIssues(sql))
7379
7403
  issues.push(issue(found.code, found.message, `migrations/${name}`));
7380
7404
  }
@@ -7479,7 +7503,7 @@ var LOCK = "flowdular.modules.lock.json";
7479
7503
  var TRANSACTION = ".flowdular-module-install";
7480
7504
  async function exists2(path) {
7481
7505
  try {
7482
- await lstat2(path);
7506
+ await lstat(path);
7483
7507
  return true;
7484
7508
  } catch (error) {
7485
7509
  if (error.code === "ENOENT") return false;
@@ -7493,10 +7517,10 @@ async function safeParents(workspace, path) {
7493
7517
  ).split("/");
7494
7518
  let current = workspace.root;
7495
7519
  for (const part of parts) {
7496
- current = join5(current, part);
7520
+ current = join4(current, part);
7497
7521
  if (!await exists2(current)) break;
7498
7522
  distributionAssert(
7499
- !(await lstat2(current)).isSymbolicLink(),
7523
+ !(await lstat(current)).isSymbolicLink(),
7500
7524
  "MODULE_DESTINATION_LINK",
7501
7525
  "Module installation paths cannot contain links."
7502
7526
  );
@@ -7536,11 +7560,11 @@ function validateLock(workspace, value) {
7536
7560
  return lock;
7537
7561
  }
7538
7562
  async function readLock(workspace) {
7539
- const path = join5(workspace.root, LOCK);
7563
+ const path = join4(workspace.root, LOCK);
7540
7564
  await safeParents(workspace, path);
7541
7565
  if (!await exists2(path))
7542
7566
  return { lock: { schemaVersion: 1, modules: [] }, raw: null };
7543
- const raw = await readFile6(path, "utf8");
7567
+ const raw = await readFile4(path, "utf8");
7544
7568
  return { lock: validateLock(workspace, JSON.parse(raw)), raw };
7545
7569
  }
7546
7570
  async function directoryHashes(root) {
@@ -7556,14 +7580,14 @@ async function directoryHashes(root) {
7556
7580
  );
7557
7581
  const path = prefix + entry.name;
7558
7582
  if (entry.isDirectory())
7559
- await visit(join5(directory, entry.name), path + "/");
7583
+ await visit(join4(directory, entry.name), path + "/");
7560
7584
  else {
7561
7585
  distributionAssert(
7562
7586
  entry.isFile(),
7563
7587
  "MODULE_LOCAL_CHANGES",
7564
7588
  "Installed module contains a special file."
7565
7589
  );
7566
- hashes[path] = hashBytes(await readFile6(join5(directory, entry.name)));
7590
+ hashes[path] = hashBytes(await readFile4(join4(directory, entry.name)));
7567
7591
  }
7568
7592
  }
7569
7593
  }
@@ -7592,8 +7616,8 @@ async function validateInstalledModules(workspace) {
7592
7616
  for (const entry of lock.modules) {
7593
7617
  await assertUnmodified(workspace, entry);
7594
7618
  const manifest2 = JSON.parse(
7595
- await readFile6(
7596
- join5(workspace.root, entry.directory, "module.json"),
7619
+ await readFile4(
7620
+ join4(workspace.root, entry.directory, "module.json"),
7597
7621
  "utf8"
7598
7622
  )
7599
7623
  );
@@ -7606,7 +7630,7 @@ async function validateInstalledModules(workspace) {
7606
7630
  return lock;
7607
7631
  }
7608
7632
  async function rollback(workspace, journal) {
7609
- const transaction = join5(workspace.root, TRANSACTION);
7633
+ const transaction = join4(workspace.root, TRANSACTION);
7610
7634
  validateLock(workspace, {
7611
7635
  schemaVersion: 1,
7612
7636
  modules: journal.entries.map((entry) => entry.installed)
@@ -7617,8 +7641,8 @@ async function rollback(workspace, journal) {
7617
7641
  entry.installed.directory
7618
7642
  );
7619
7643
  await safeParents(workspace, destination);
7620
- const backup = join5(transaction, `backup-${index}`);
7621
- const moved = !await exists2(join5(transaction, `stage-${index}`));
7644
+ const backup = join4(transaction, `backup-${index}`);
7645
+ const moved = !await exists2(join4(transaction, `stage-${index}`));
7622
7646
  if (moved && await exists2(destination)) {
7623
7647
  const hashes = await directoryHashes(destination);
7624
7648
  if (equalHashes(hashes, entry.installed.files))
@@ -7640,9 +7664,9 @@ async function rollback(workspace, journal) {
7640
7664
  await rename(backup, destination);
7641
7665
  }
7642
7666
  }
7643
- const lockPath = join5(workspace.root, LOCK);
7667
+ const lockPath = join4(workspace.root, LOCK);
7644
7668
  await safeParents(workspace, lockPath);
7645
- const current = await exists2(lockPath) ? await readFile6(lockPath, "utf8") : null;
7669
+ const current = await exists2(lockPath) ? await readFile4(lockPath, "utf8") : null;
7646
7670
  distributionAssert(
7647
7671
  current === journal.previous || current === journal.next,
7648
7672
  "MODULE_RECOVERY_CONFLICT",
@@ -7652,13 +7676,13 @@ async function rollback(workspace, journal) {
7652
7676
  else await writeFile(lockPath, journal.previous);
7653
7677
  }
7654
7678
  async function recoverModuleInstall(workspace, apply) {
7655
- const transaction = join5(workspace.root, TRANSACTION);
7679
+ const transaction = join4(workspace.root, TRANSACTION);
7656
7680
  await safeParents(workspace, transaction);
7657
7681
  if (!await exists2(transaction)) return { recovered: false, pending: false };
7658
- const hasJournal = await exists2(join5(transaction, "journal.json"));
7682
+ const hasJournal = await exists2(join4(transaction, "journal.json"));
7659
7683
  const journal = JSON.parse(
7660
- await readFile6(
7661
- join5(transaction, hasJournal ? "journal.json" : "owner.json"),
7684
+ await readFile4(
7685
+ join4(transaction, hasJournal ? "journal.json" : "owner.json"),
7662
7686
  "utf8"
7663
7687
  )
7664
7688
  );
@@ -7684,7 +7708,7 @@ async function recoverModuleInstall(workspace, apply) {
7684
7708
  return { recovered: true, pending: false };
7685
7709
  }
7686
7710
  async function installPlannedModule(workspace, options) {
7687
- const transaction = join5(workspace.root, TRANSACTION);
7711
+ const transaction = join4(workspace.root, TRANSACTION);
7688
7712
  await safeParents(workspace, transaction);
7689
7713
  distributionAssert(
7690
7714
  !await exists2(transaction),
@@ -7701,7 +7725,7 @@ async function installPlannedModule(workspace, options) {
7701
7725
  for (const root of moduleRoots(workspace)) await safeParents(workspace, root);
7702
7726
  const files = await findModuleFiles(workspace);
7703
7727
  for (const file of files)
7704
- manifests.push(JSON.parse(await readFile6(file, "utf8")));
7728
+ manifests.push(JSON.parse(await readFile4(file, "utf8")));
7705
7729
  const id = options.target.split("@")[0];
7706
7730
  const previous = snapshot.lock.modules.find((entry) => entry.id === id);
7707
7731
  distributionAssert(
@@ -7764,7 +7788,7 @@ async function installPlannedModule(workspace, options) {
7764
7788
  "Catalog and artifact manifest differ."
7765
7789
  );
7766
7790
  const old = snapshot.lock.modules.find((entry) => entry.id === release.manifest.id) ?? null;
7767
- const destination = old ? resolveInside(workspace.root, old.directory) : join5(
7791
+ const destination = old ? resolveInside(workspace.root, old.directory) : join4(
7768
7792
  moduleRoots(workspace)[0],
7769
7793
  release.manifest.package.replace("@flowdular/module-", "")
7770
7794
  );
@@ -7839,14 +7863,14 @@ async function installPlannedModule(workspace, options) {
7839
7863
  let journalWritten = false;
7840
7864
  try {
7841
7865
  await writeFile(
7842
- join5(transaction, "owner.json"),
7866
+ join4(transaction, "owner.json"),
7843
7867
  JSON.stringify({ schemaVersion: 1, pid: process.pid })
7844
7868
  );
7845
7869
  for (const [index, entry] of entries.entries()) {
7846
- const stage = join5(transaction, `stage-${index}`);
7870
+ const stage = join4(transaction, `stage-${index}`);
7847
7871
  await mkdir(stage);
7848
7872
  for (const file of entry.artifact.files) {
7849
- const path = join5(stage, file.path);
7873
+ const path = join4(stage, file.path);
7850
7874
  await mkdir(dirname5(path), { recursive: true });
7851
7875
  await writeFile(path, Buffer.from(file.content, "base64"), {
7852
7876
  flag: "wx"
@@ -7859,10 +7883,10 @@ async function installPlannedModule(workspace, options) {
7859
7883
  `Invalid module layout: ${issues.map((issue2) => issue2.message).join("; ")}`
7860
7884
  );
7861
7885
  }
7862
- await writeFile(join5(transaction, "journal.tmp"), JSON.stringify(journal));
7886
+ await writeFile(join4(transaction, "journal.tmp"), JSON.stringify(journal));
7863
7887
  await rename(
7864
- join5(transaction, "journal.tmp"),
7865
- join5(transaction, "journal.json")
7888
+ join4(transaction, "journal.tmp"),
7889
+ join4(transaction, "journal.json")
7866
7890
  );
7867
7891
  journalWritten = true;
7868
7892
  distributionAssert(
@@ -7878,7 +7902,7 @@ async function installPlannedModule(workspace, options) {
7878
7902
  await safeParents(workspace, destination);
7879
7903
  if (entry.previous) {
7880
7904
  await assertUnmodified(workspace, entry.previous);
7881
- await rename(destination, join5(transaction, `backup-${index}`));
7905
+ await rename(destination, join4(transaction, `backup-${index}`));
7882
7906
  } else
7883
7907
  distributionAssert(
7884
7908
  !await exists2(destination),
@@ -7886,43 +7910,325 @@ async function installPlannedModule(workspace, options) {
7886
7910
  `Destination appeared during installation: ${entry.installed.directory}`
7887
7911
  );
7888
7912
  await mkdir(dirname5(destination), { recursive: true });
7889
- await rename(join5(transaction, `stage-${index}`), destination);
7913
+ await rename(join4(transaction, `stage-${index}`), destination);
7890
7914
  }
7891
- await writeFile(join5(transaction, "next-lock.json"), journal.next);
7915
+ await writeFile(join4(transaction, "next-lock.json"), journal.next);
7892
7916
  await rename(
7893
- join5(transaction, "next-lock.json"),
7894
- join5(workspace.root, LOCK)
7917
+ join4(transaction, "next-lock.json"),
7918
+ join4(workspace.root, LOCK)
7919
+ );
7920
+ } catch (error) {
7921
+ if (journalWritten) await rollback(workspace, journal);
7922
+ await rm(transaction, { recursive: true });
7923
+ throw error;
7924
+ }
7925
+ await rm(transaction, { recursive: true });
7926
+ return {
7927
+ applied: true,
7928
+ modules: entries.map((entry) => entry.installed),
7929
+ activationRequired: true
7930
+ };
7931
+ }
7932
+
7933
+ // ../database-pglite/src/driver.ts
7934
+ import { PGlite } from "@electric-sql/pglite";
7935
+ import { mkdir as mkdir2, readFile as readFile5, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
7936
+ import { join as join5, resolve as resolve5 } from "node:path";
7937
+ var ROLE = /^[a-z_][a-z0-9_]{0,62}$/;
7938
+ var LOCK_FILE = "flowdular.lock";
7939
+ var LocalDatabaseLockedError = class extends Error {
7940
+ constructor(directory, pid) {
7941
+ super(
7942
+ `The local database in ${directory} is already open in process ${pid}. Stop that Flowdular first, or point this one at another directory with FD_DATABASE_PGLITE_DIRECTORY.`
7943
+ );
7944
+ this.directory = directory;
7945
+ this.pid = pid;
7946
+ this.name = "LocalDatabaseLockedError";
7947
+ }
7948
+ directory;
7949
+ pid;
7950
+ code = "LOCAL_DATABASE_LOCKED";
7951
+ };
7952
+ var LocalDatabaseUnreadableError = class extends Error {
7953
+ constructor(directory, cause) {
7954
+ super(
7955
+ `The local database in ${directory} could not be opened. A process killed mid write leaves it this way. Restore a backup of that directory, recreate the workspace with "pnpm flowdular setup quick --apply --confirm reset-local-auth", or point somewhere else with FD_DATABASE_PGLITE_DIRECTORY.`,
7956
+ { cause }
7957
+ );
7958
+ this.directory = directory;
7959
+ this.name = "LocalDatabaseUnreadableError";
7960
+ }
7961
+ directory;
7962
+ code = "LOCAL_DATABASE_UNREADABLE";
7963
+ };
7964
+ function running(pid) {
7965
+ try {
7966
+ process.kill(pid, 0);
7967
+ return true;
7968
+ } catch (error) {
7969
+ return error.code === "EPERM";
7970
+ }
7971
+ }
7972
+ async function claimDirectory(directory) {
7973
+ const path = join5(directory, LOCK_FILE);
7974
+ let held;
7975
+ try {
7976
+ held = await readFile5(path, "utf8");
7977
+ } catch (error) {
7978
+ if (error.code !== "ENOENT") throw error;
7979
+ }
7980
+ const pid = Number(held?.split("\n")[0]);
7981
+ if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && running(pid)) {
7982
+ throw new LocalDatabaseLockedError(directory, pid);
7983
+ }
7984
+ await writeFile2(path, `${process.pid}
7985
+ ${(/* @__PURE__ */ new Date()).toISOString()}
7986
+ `, {
7987
+ mode: 384
7988
+ });
7989
+ }
7990
+ async function releaseDirectory(directory) {
7991
+ const path = join5(directory, LOCK_FILE);
7992
+ try {
7993
+ const held = await readFile5(path, "utf8");
7994
+ if (Number(held.split("\n")[0]) !== process.pid) return;
7995
+ await rm2(path, { force: true });
7996
+ } catch (error) {
7997
+ const code = error.code;
7998
+ if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") return;
7999
+ throw error;
8000
+ }
8001
+ }
8002
+ var INT8_OID = 20;
8003
+ var SERVER_PARSERS = Object.freeze({ [INT8_OID]: (value) => value });
8004
+ var ConnectionQueue = class {
8005
+ #tail = Promise.resolve();
8006
+ acquire() {
8007
+ let release;
8008
+ const held = new Promise((resolve11) => {
8009
+ release = resolve11;
8010
+ });
8011
+ const waited = this.#tail.then(() => release);
8012
+ this.#tail = this.#tail.then(() => held);
8013
+ return waited;
8014
+ }
8015
+ };
8016
+ function result(rows, affected) {
8017
+ return {
8018
+ rows,
8019
+ rowCount: rows.length > 0 ? rows.length : affected
8020
+ };
8021
+ }
8022
+ async function openDatabase(directory, bootstrap) {
8023
+ if (directory) {
8024
+ await mkdir2(directory, { recursive: true, mode: 448 });
8025
+ await claimDirectory(directory);
8026
+ }
8027
+ let created;
8028
+ try {
8029
+ created = directory ? await PGlite.create({
8030
+ dataDir: directory,
8031
+ parsers: SERVER_PARSERS
8032
+ }) : await PGlite.create({ parsers: SERVER_PARSERS });
8033
+ } catch (error) {
8034
+ if (!directory) throw error;
8035
+ await releaseDirectory(directory);
8036
+ throw new LocalDatabaseUnreadableError(directory, error);
8037
+ }
8038
+ try {
8039
+ if (bootstrap) await created.exec(bootstrap);
8040
+ } catch (error) {
8041
+ try {
8042
+ await created.close();
8043
+ } catch (closeError) {
8044
+ throw new AggregateError(
8045
+ [error, closeError],
8046
+ "PGlite bootstrap failed and cleanup also failed."
8047
+ );
8048
+ }
8049
+ throw error;
8050
+ }
8051
+ return created;
8052
+ }
8053
+ var OPEN_DIRECTORIES = /* @__PURE__ */ Symbol.for("flowdular.database-pglite.directories");
8054
+ function openDirectories() {
8055
+ const host = globalThis;
8056
+ host[OPEN_DIRECTORIES] ??= { open: /* @__PURE__ */ new Map(), closing: /* @__PURE__ */ new Map() };
8057
+ return host[OPEN_DIRECTORIES];
8058
+ }
8059
+ function attachDatabase(directory, bootstrap) {
8060
+ if (!directory) {
8061
+ return {
8062
+ queue: new ConnectionQueue(),
8063
+ instance: openDatabase(void 0, bootstrap),
8064
+ holders: 1
8065
+ };
8066
+ }
8067
+ const key = resolve5(directory);
8068
+ const directories = openDirectories();
8069
+ let database = directories.open.get(key);
8070
+ if (!database) {
8071
+ const previousClose = directories.closing.get(key) ?? Promise.resolve();
8072
+ const opening = {
8073
+ queue: new ConnectionQueue(),
8074
+ instance: previousClose.then(() => openDatabase(directory, bootstrap)),
8075
+ holders: 0
8076
+ };
8077
+ opening.instance.catch(() => {
8078
+ if (directories.open.get(key) === opening) directories.open.delete(key);
8079
+ });
8080
+ directories.open.set(key, opening);
8081
+ database = opening;
8082
+ }
8083
+ database.holders += 1;
8084
+ return database;
8085
+ }
8086
+ async function detachDatabase(directory, database) {
8087
+ database.holders -= 1;
8088
+ if (database.holders > 0) return;
8089
+ const directories = openDirectories();
8090
+ const key = directory ? resolve5(directory) : void 0;
8091
+ const current = key ? directories.open.get(key) : void 0;
8092
+ if (key && current === database) directories.open.delete(key);
8093
+ const ownsDirectory = directory !== void 0 && (current === void 0 || current === database);
8094
+ const closed = (async () => {
8095
+ const instance = await database.instance.catch(() => void 0);
8096
+ await instance?.close();
8097
+ if (ownsDirectory) await releaseDirectory(directory);
8098
+ })();
8099
+ if (key && ownsDirectory) {
8100
+ const settled = closed.catch(() => void 0);
8101
+ directories.closing.set(key, settled);
8102
+ void settled.then(() => {
8103
+ if (directories.closing.get(key) === settled)
8104
+ directories.closing.delete(key);
8105
+ });
8106
+ }
8107
+ await closed;
8108
+ }
8109
+ function createPgliteCluster(options = {}) {
8110
+ let database;
8111
+ let closing;
8112
+ let issued = 0;
8113
+ let ended = 0;
8114
+ const close = () => {
8115
+ const attached = database;
8116
+ if (!attached) return closing ?? Promise.resolve();
8117
+ database = void 0;
8118
+ closing = detachDatabase(options.dataDirectory, attached);
8119
+ return closing;
8120
+ };
8121
+ const pool = (role) => {
8122
+ if (role !== void 0 && !ROLE.test(role)) {
8123
+ throw new Error(`"${role}" is not a usable PostgreSQL role name.`);
8124
+ }
8125
+ issued += 1;
8126
+ return {
8127
+ cancellation: "before-start",
8128
+ async connect() {
8129
+ database ??= attachDatabase(options.dataDirectory, options.bootstrap);
8130
+ const attached = database;
8131
+ const release = await attached.queue.acquire();
8132
+ let instance;
8133
+ try {
8134
+ instance = await attached.instance;
8135
+ if (role) await instance.exec(`SET ROLE ${role}`);
8136
+ } catch (error) {
8137
+ release();
8138
+ throw error;
8139
+ }
8140
+ let released = false;
8141
+ const run = async ({
8142
+ text,
8143
+ values: values2
8144
+ }) => {
8145
+ if (values2 === void 0 || values2.length === 0) {
8146
+ const answers = await instance.exec(text);
8147
+ const last = answers[answers.length - 1];
8148
+ return last ? result(last.rows, last.affectedRows ?? 0) : result([], 0);
8149
+ }
8150
+ const answer = await instance.query(text, [...values2]);
8151
+ return result(answer.rows, answer.affectedRows ?? 0);
8152
+ };
8153
+ return {
8154
+ query: run,
8155
+ release() {
8156
+ if (released) return;
8157
+ released = true;
8158
+ const reset = role ? instance.exec("RESET ROLE").catch(() => void 0) : Promise.resolve();
8159
+ void reset.finally(release);
8160
+ }
8161
+ };
8162
+ },
8163
+ async end() {
8164
+ ended += 1;
8165
+ if (ended < issued) return;
8166
+ await close();
8167
+ }
8168
+ };
8169
+ };
8170
+ return { pool, close };
8171
+ }
8172
+
8173
+ // ../kernel/src/legacy-local-state.ts
8174
+ var LEGACY_DATA_DIRECTORY = ".octane-erp";
8175
+ var LegacyLocalStateError = class extends Error {
8176
+ constructor(fileName) {
8177
+ super(
8178
+ `Legacy local state exists for ${fileName}. Stop Flowdular and run "flowdular setup migrate-state" before starting it again.`
7895
8179
  );
7896
- } catch (error) {
7897
- if (journalWritten) await rollback(workspace, journal);
7898
- await rm(transaction, { recursive: true });
7899
- throw error;
8180
+ this.fileName = fileName;
8181
+ this.name = "LegacyLocalStateError";
7900
8182
  }
7901
- await rm(transaction, { recursive: true });
7902
- return {
7903
- applied: true,
7904
- modules: entries.map((entry) => entry.installed),
7905
- activationRequired: true
7906
- };
8183
+ fileName;
8184
+ code = "LEGACY_LOCAL_STATE_REQUIRES_MIGRATION";
8185
+ };
8186
+
8187
+ // src/command-failure.ts
8188
+ var STABLE_CODE = /^[A-Z][A-Z0-9_]{0,63}$/;
8189
+ var PLATFORM_ERRORS = [
8190
+ ModuleDistributionError,
8191
+ RegistryError,
8192
+ KeyringError,
8193
+ LegacyLocalStateError,
8194
+ UnsafeLocalStatePathError,
8195
+ VariableResolutionError,
8196
+ DatabaseMigrationError,
8197
+ DatabaseError,
8198
+ LocalDatabaseLockedError,
8199
+ LocalDatabaseUnreadableError
8200
+ ];
8201
+ function isModuleRefusal(error) {
8202
+ return typeof error.status === "number";
8203
+ }
8204
+ function commandFailure(error) {
8205
+ if (!(error instanceof Error))
8206
+ return failure("COMMAND_FAILED", String(error));
8207
+ const code = error.code;
8208
+ const known = PLATFORM_ERRORS.some((type) => error instanceof type) || isModuleRefusal(error);
8209
+ return failure(
8210
+ known && typeof code === "string" && STABLE_CODE.test(code) ? code : "COMMAND_FAILED",
8211
+ error.message
8212
+ );
7907
8213
  }
7908
8214
 
7909
8215
  // src/module-plans.ts
7910
8216
  import {
7911
- readFile as readFile9,
8217
+ readFile as readFile8,
7912
8218
  readdir as readdir4,
7913
- mkdir as mkdir3,
8219
+ mkdir as mkdir4,
7914
8220
  rename as rename3,
7915
- writeFile as writeFile3,
7916
- rm as rm3,
7917
- lstat as lstat4
8221
+ writeFile as writeFile4,
8222
+ rm as rm4,
8223
+ lstat as lstat3
7918
8224
  } from "node:fs/promises";
7919
8225
  import { randomUUID as randomUUID2 } from "node:crypto";
7920
8226
  import { join as join7, relative as relative6 } from "node:path";
7921
8227
  import { parse as parseYaml4 } from "yaml";
7922
8228
 
7923
8229
  // src/module-catalog.ts
7924
- import { readFile as readFile7, stat } from "node:fs/promises";
7925
- import { dirname as dirname6, resolve as resolve4 } from "node:path";
8230
+ import { readFile as readFile6, stat } from "node:fs/promises";
8231
+ import { dirname as dirname6, resolve as resolve6 } from "node:path";
7926
8232
  function platformAdmits(manifest2) {
7927
8233
  try {
7928
8234
  assertModuleCompatibility(manifest2);
@@ -7938,7 +8244,7 @@ async function boundedRead(location, limit, fetcher = fetch) {
7938
8244
  "MODULE_DOWNLOAD_LIMIT",
7939
8245
  "Module metadata/artifact exceeds the size limit."
7940
8246
  );
7941
- const result2 = await readFile7(location);
8247
+ const result2 = await readFile6(location);
7942
8248
  distributionAssert(
7943
8249
  result2.length <= limit,
7944
8250
  "MODULE_DOWNLOAD_LIMIT",
@@ -8030,7 +8336,7 @@ async function releaseLocation(source, release) {
8030
8336
  "An offline catalog must use local artifacts."
8031
8337
  );
8032
8338
  return resolveExistingInside(
8033
- dirname6(resolve4(source.location)),
8339
+ dirname6(resolve6(source.location)),
8034
8340
  release.artifact
8035
8341
  );
8036
8342
  }
@@ -8141,16 +8447,16 @@ async function readRelease(source, release, fetcher = fetch) {
8141
8447
  import { execFile } from "node:child_process";
8142
8448
  import { randomUUID } from "node:crypto";
8143
8449
  import {
8144
- lstat as lstat3,
8145
- mkdir as mkdir2,
8450
+ lstat as lstat2,
8451
+ mkdir as mkdir3,
8146
8452
  mkdtemp,
8147
- readFile as readFile8,
8453
+ readFile as readFile7,
8148
8454
  rename as rename2,
8149
- rm as rm2,
8150
- writeFile as writeFile2
8455
+ rm as rm3,
8456
+ writeFile as writeFile3
8151
8457
  } from "node:fs/promises";
8152
8458
  import { tmpdir } from "node:os";
8153
- import { isAbsolute as isAbsolute2, join as join6, resolve as resolve5 } from "node:path";
8459
+ import { isAbsolute as isAbsolute3, join as join6, resolve as resolve7 } from "node:path";
8154
8460
  import { promisify } from "node:util";
8155
8461
  var exec = promisify(execFile);
8156
8462
  var SOURCES_FILE = "flowdular.module-sources.json";
@@ -8188,13 +8494,13 @@ function validateSource(source) {
8188
8494
  async function readModuleSources(workspace) {
8189
8495
  let raw;
8190
8496
  try {
8191
- const info = await lstat3(sourcePath(workspace));
8497
+ const info = await lstat2(sourcePath(workspace));
8192
8498
  distributionAssert(
8193
8499
  info.isFile() && !info.isSymbolicLink() && info.size <= 64 * 1024,
8194
8500
  "MODULE_SOURCE_INVALID",
8195
8501
  "Module source list is not a bounded regular file."
8196
8502
  );
8197
- raw = await readFile8(sourcePath(workspace), "utf8");
8503
+ raw = await readFile7(sourcePath(workspace), "utf8");
8198
8504
  } catch (error) {
8199
8505
  if (error.code === "ENOENT") return [];
8200
8506
  throw error;
@@ -8252,7 +8558,7 @@ async function updateSources(workspace, apply, change) {
8252
8558
  const destination = sourcePath(workspace);
8253
8559
  const lock = destination + ".lock";
8254
8560
  try {
8255
- await mkdir2(lock);
8561
+ await mkdir3(lock);
8256
8562
  } catch (error) {
8257
8563
  if (error.code === "EEXIST")
8258
8564
  distributionAssert(
@@ -8265,7 +8571,7 @@ async function updateSources(workspace, apply, change) {
8265
8571
  try {
8266
8572
  const sources = change(await readModuleSources(workspace));
8267
8573
  const temp = destination + "." + randomUUID() + ".tmp";
8268
- await writeFile2(
8574
+ await writeFile3(
8269
8575
  temp,
8270
8576
  JSON.stringify({ schemaVersion: 1, sources }, null, " ") + "\n",
8271
8577
  { flag: "wx" }
@@ -8273,11 +8579,11 @@ async function updateSources(workspace, apply, change) {
8273
8579
  try {
8274
8580
  await rename2(temp, destination);
8275
8581
  } finally {
8276
- await rm2(temp, { force: true });
8582
+ await rm3(temp, { force: true });
8277
8583
  }
8278
8584
  return { sources, applied: true };
8279
8585
  } finally {
8280
- await rm2(lock, { recursive: true, force: true });
8586
+ await rm3(lock, { recursive: true, force: true });
8281
8587
  }
8282
8588
  }
8283
8589
  async function git(directory, ...arguments_) {
@@ -8295,12 +8601,12 @@ async function git(directory, ...arguments_) {
8295
8601
  async function withModuleSource(workspace, source, work) {
8296
8602
  validateSource(source);
8297
8603
  if (source.kind === "catalog") {
8298
- const location = source.location.startsWith("https://") ? source.location : resolve5(workspace.root, source.location);
8604
+ const location = source.location.startsWith("https://") ? source.location : resolve7(workspace.root, source.location);
8299
8605
  return work(await loadModuleCatalog(location));
8300
8606
  }
8301
8607
  const checkout = await mkdtemp(join6(tmpdir(), "flowdular-module-source-"));
8302
8608
  try {
8303
- const location = source.location.startsWith("https://") ? source.location : isAbsolute2(source.location) ? source.location : resolve5(workspace.root, source.location);
8609
+ const location = source.location.startsWith("https://") ? source.location : isAbsolute3(source.location) ? source.location : resolve7(workspace.root, source.location);
8304
8610
  await git(checkout, "init", "-q");
8305
8611
  await git(
8306
8612
  checkout,
@@ -8322,7 +8628,7 @@ async function withModuleSource(workspace, source, work) {
8322
8628
  );
8323
8629
  return await work(await loadModuleCatalog(catalogPath));
8324
8630
  } finally {
8325
- await rm2(checkout, { recursive: true, force: true });
8631
+ await rm3(checkout, { recursive: true, force: true });
8326
8632
  }
8327
8633
  }
8328
8634
 
@@ -8347,7 +8653,7 @@ function checkedPlanFiles(files) {
8347
8653
  async function planCollectionBytes(directory, files) {
8348
8654
  let total = 0;
8349
8655
  for (const file of files) {
8350
- const info = await lstat4(join7(directory, file));
8656
+ const info = await lstat3(join7(directory, file));
8351
8657
  distributionAssert(
8352
8658
  info.isFile() && !info.isSymbolicLink() && info.size <= MAX_PLAN_BYTES,
8353
8659
  "MODULE_PLAN_INVALID",
@@ -8359,7 +8665,7 @@ async function planCollectionBytes(directory, files) {
8359
8665
  }
8360
8666
  async function checkedPlanDirectory(workspace) {
8361
8667
  const directory = planDirectory(workspace);
8362
- const info = await lstat4(directory);
8668
+ const info = await lstat3(directory);
8363
8669
  distributionAssert(
8364
8670
  info.isDirectory() && !info.isSymbolicLink(),
8365
8671
  "MODULE_PLAN_INVALID",
@@ -8370,7 +8676,7 @@ async function checkedPlanDirectory(workspace) {
8370
8676
  async function lockDigest(workspace) {
8371
8677
  try {
8372
8678
  return hashBytes(
8373
- await readFile9(join7(workspace.root, "flowdular.modules.lock.json"))
8679
+ await readFile8(join7(workspace.root, "flowdular.modules.lock.json"))
8374
8680
  );
8375
8681
  } catch (error) {
8376
8682
  if (error.code === "ENOENT") return null;
@@ -8383,7 +8689,7 @@ async function workspaceDigest(workspace) {
8383
8689
  for (const file of files)
8384
8690
  manifests.push([
8385
8691
  relative6(workspace.root, file),
8386
- hashBytes(await readFile9(file))
8692
+ hashBytes(await readFile8(file))
8387
8693
  ]);
8388
8694
  return hashBytes(
8389
8695
  JSON.stringify(manifests.sort(([a], [b]) => a.localeCompare(b)))
@@ -8416,7 +8722,7 @@ function permissions(artifact) {
8416
8722
  async function plannedReleases(workspace, source, target, update) {
8417
8723
  const manifests = [];
8418
8724
  for (const file of await findModuleFiles(workspace))
8419
- manifests.push(JSON.parse(await readFile9(file, "utf8")));
8725
+ manifests.push(JSON.parse(await readFile8(file, "utf8")));
8420
8726
  const targetId = target.split("@")[0];
8421
8727
  if (update) {
8422
8728
  const lock = await validateInstalledModules(workspace);
@@ -8531,7 +8837,7 @@ async function createModulePlan(workspace, options) {
8531
8837
  );
8532
8838
  const lock = planDirectory(workspace) + ".lock";
8533
8839
  try {
8534
- await mkdir3(lock);
8840
+ await mkdir4(lock);
8535
8841
  } catch (error) {
8536
8842
  if (error.code === "EEXIST")
8537
8843
  distributionAssert(
@@ -8543,7 +8849,7 @@ async function createModulePlan(workspace, options) {
8543
8849
  }
8544
8850
  try {
8545
8851
  const directory = planDirectory(workspace);
8546
- await mkdir3(directory, { recursive: true });
8852
+ await mkdir4(directory, { recursive: true });
8547
8853
  await checkedPlanDirectory(workspace);
8548
8854
  const files = await readdir4(directory);
8549
8855
  checkedPlanFiles(files);
@@ -8560,10 +8866,10 @@ async function createModulePlan(workspace, options) {
8560
8866
  "The workspace has 8 MiB of module plans. Remove an obsolete plan first."
8561
8867
  );
8562
8868
  const temp = join7(lock, `${randomUUID2()}.tmp`);
8563
- await writeFile3(temp, serialized, { flag: "wx" });
8869
+ await writeFile4(temp, serialized, { flag: "wx" });
8564
8870
  await rename3(temp, join7(directory, name));
8565
8871
  } finally {
8566
- await rm3(lock, { recursive: true, force: true });
8872
+ await rm4(lock, { recursive: true, force: true });
8567
8873
  }
8568
8874
  }
8569
8875
  return plan;
@@ -8575,13 +8881,13 @@ async function readModulePlan(workspace, id) {
8575
8881
  "Invalid module plan id."
8576
8882
  );
8577
8883
  const path = join7(await checkedPlanDirectory(workspace), `${id}.json`);
8578
- const info = await lstat4(path);
8884
+ const info = await lstat3(path);
8579
8885
  distributionAssert(
8580
8886
  info.isFile() && !info.isSymbolicLink() && info.size <= MAX_PLAN_BYTES,
8581
8887
  "MODULE_PLAN_INVALID",
8582
8888
  "Module plan is not a bounded regular file."
8583
8889
  );
8584
- const raw = await readFile9(path, "utf8");
8890
+ const raw = await readFile8(path, "utf8");
8585
8891
  const plan = JSON.parse(raw);
8586
8892
  distributionAssert(
8587
8893
  plan && typeof plan === "object",
@@ -8620,7 +8926,7 @@ async function listModulePlans(workspace) {
8620
8926
  }
8621
8927
  async function removeModulePlan(workspace, id, apply) {
8622
8928
  await readModulePlan(workspace, id);
8623
- if (apply) await rm3(join7(planDirectory(workspace), `${id}.json`));
8929
+ if (apply) await rm4(join7(planDirectory(workspace), `${id}.json`));
8624
8930
  return { id, applied: apply };
8625
8931
  }
8626
8932
  async function applyModulePlan(workspace, id, apply) {
@@ -8657,15 +8963,78 @@ async function applyModulePlan(workspace, id, apply) {
8657
8963
  }
8658
8964
 
8659
8965
  // src/web-mounts.ts
8660
- import { readFile as readFile11 } from "node:fs/promises";
8966
+ import { readFile as readFile10 } from "node:fs/promises";
8967
+
8968
+ // src/sdk.ts
8969
+ var SDK_VERSION = "0.6.2";
8970
+ var LIBRARIES = /* @__PURE__ */ new Set([
8971
+ "ai-provider",
8972
+ "cli-protocol",
8973
+ "client",
8974
+ "contracts",
8975
+ "database",
8976
+ "database-pglite",
8977
+ "database-testing",
8978
+ "dev-console",
8979
+ "harness",
8980
+ "kernel",
8981
+ "server",
8982
+ "storage",
8983
+ "ui"
8984
+ ]);
8985
+ var CORE_MODULES = /* @__PURE__ */ new Set([
8986
+ "agents",
8987
+ "auth",
8988
+ "automations",
8989
+ "profile",
8990
+ "sandbox",
8991
+ "system",
8992
+ "users",
8993
+ "workflows"
8994
+ ]);
8995
+ function sdkSpecifier(name) {
8996
+ const suffix = name.slice("@flowdular/".length);
8997
+ if (!name.startsWith("@flowdular/")) return name;
8998
+ if (LIBRARIES.has(suffix)) return `@flowdular/sdk/${suffix}`;
8999
+ if (suffix.startsWith("module-") && CORE_MODULES.has(suffix.slice(7)))
9000
+ return `@flowdular/sdk/modules/${suffix.slice(7)}`;
9001
+ return name;
9002
+ }
9003
+ function sdkSource(source) {
9004
+ return source.replace(/@flowdular\/[a-z0-9-]+/g, sdkSpecifier);
9005
+ }
9006
+ function npmPackage(specifier) {
9007
+ return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
9008
+ }
9009
+ async function sdkModules(workspace) {
9010
+ return sdkModuleManifests(workspace.root);
9011
+ }
9012
+ function sdkScaffold(files) {
9013
+ return new Map(
9014
+ [...files].map(([path, source]) => {
9015
+ if (path === "spec/module.yaml" || path === "module.json")
9016
+ return [path, source];
9017
+ if (path !== "package.json") return [path, sdkSource(source)];
9018
+ const pkg = JSON.parse(source);
9019
+ for (const section of [pkg.dependencies, pkg.devDependencies])
9020
+ if (section) {
9021
+ for (const name of Object.keys(section))
9022
+ if (sdkSpecifier(name) !== name) delete section[name];
9023
+ }
9024
+ pkg.dependencies ??= {};
9025
+ pkg.dependencies["@flowdular/sdk"] = SDK_VERSION;
9026
+ return [path, JSON.stringify(pkg, null, " ") + "\n"];
9027
+ })
9028
+ );
9029
+ }
8661
9030
 
8662
9031
  // src/module-sync.ts
8663
9032
  import { spawnSync } from "node:child_process";
8664
- import { access as access3, mkdir as mkdir4, readFile as readFile10, rm as rm4, writeFile as writeFile4 } from "node:fs/promises";
9033
+ import { access as access3, mkdir as mkdir5, readFile as readFile9, rm as rm5, writeFile as writeFile5 } from "node:fs/promises";
8665
9034
  import { dirname as dirname7, join as join9 } from "node:path";
8666
9035
 
8667
9036
  // src/format.ts
8668
- import { createRequire as createRequire3 } from "node:module";
9037
+ import { createRequire as createRequire2 } from "node:module";
8669
9038
  import { join as join8 } from "node:path";
8670
9039
  import { pathToFileURL } from "node:url";
8671
9040
  var DEFAULT_OPTIONS = {
@@ -8677,7 +9046,7 @@ var TSRX_PLUGIN = "@tsrx/prettier-plugin";
8677
9046
  function resolveFrom(workspaceRoot, specifier) {
8678
9047
  for (const base of [join8(workspaceRoot, "package.json"), import.meta.url]) {
8679
9048
  try {
8680
- return createRequire3(base).resolve(specifier);
9049
+ return createRequire2(base).resolve(specifier);
8681
9050
  } catch {
8682
9051
  }
8683
9052
  }
@@ -8721,7 +9090,7 @@ async function writeProjectConfig(workspace, config) {
8721
9090
  const raw = JSON.stringify(config, null, " ") + "\n";
8722
9091
  const formatter = await loadWorkspaceFormatter(workspace.root);
8723
9092
  const output = formatter ? await formatter.format(workspace.configPath, raw) : raw;
8724
- await writeFile4(workspace.configPath, output);
9093
+ await writeFile5(workspace.configPath, output);
8725
9094
  }
8726
9095
  var PROTECTED_MODULES = ["system.core", "auth.core"];
8727
9096
  var GENERATED_FILES = {
@@ -8793,7 +9162,7 @@ async function loadManifests(workspace) {
8793
9162
  const descriptors = /* @__PURE__ */ new Map();
8794
9163
  for (const file of files) {
8795
9164
  const manifest2 = JSON.parse(
8796
- await readFile10(file, "utf8")
9165
+ await readFile9(file, "utf8")
8797
9166
  );
8798
9167
  if (!validators.module(manifest2))
8799
9168
  throw new Error(`Invalid module manifest: ${file}`);
@@ -8898,7 +9267,7 @@ async function takeSnapshots(paths) {
8898
9267
  return Promise.all(
8899
9268
  paths.map(async (path) => {
8900
9269
  try {
8901
- return { path, content: await readFile10(path, "utf8") };
9270
+ return { path, content: await readFile9(path, "utf8") };
8902
9271
  } catch (error) {
8903
9272
  if (error.code === "ENOENT") {
8904
9273
  return { path, content: void 0 };
@@ -8911,11 +9280,11 @@ async function takeSnapshots(paths) {
8911
9280
  async function restoreSnapshots(snapshots) {
8912
9281
  for (const snapshot of [...snapshots].reverse()) {
8913
9282
  if (snapshot.content === void 0) {
8914
- await rm4(snapshot.path, { force: true });
9283
+ await rm5(snapshot.path, { force: true });
8915
9284
  continue;
8916
9285
  }
8917
- await mkdir4(dirname7(snapshot.path), { recursive: true });
8918
- await writeFile4(snapshot.path, snapshot.content);
9286
+ await mkdir5(dirname7(snapshot.path), { recursive: true });
9287
+ await writeFile5(snapshot.path, snapshot.content);
8919
9288
  }
8920
9289
  }
8921
9290
  async function syncPlatformModules(workspace, apply, enabledOverride) {
@@ -8956,13 +9325,13 @@ async function syncPlatformModules(workspace, apply, enabledOverride) {
8956
9325
  const absolute = join9(workspace.root, target.path);
8957
9326
  let current = "";
8958
9327
  try {
8959
- current = await readFile10(absolute, "utf8");
9328
+ current = await readFile9(absolute, "utf8");
8960
9329
  } catch {
8961
9330
  }
8962
9331
  const changed = current !== target.content;
8963
9332
  if (apply && changed) {
8964
- await mkdir4(dirname7(absolute), { recursive: true });
8965
- await writeFile4(absolute, target.content);
9333
+ await mkdir5(dirname7(absolute), { recursive: true });
9334
+ await writeFile5(absolute, target.content);
8966
9335
  }
8967
9336
  files.push({ path: target.path, changed });
8968
9337
  }
@@ -8987,7 +9356,7 @@ async function enableModule(workspace, id, apply) {
8987
9356
  const configChanged = !equalIds(current, enabled);
8988
9357
  const platformPackagePath = join9(workspace.root, "platform/package.json");
8989
9358
  const platformPackage = JSON.parse(
8990
- await readFile10(platformPackagePath, "utf8")
9359
+ await readFile9(platformPackagePath, "utf8")
8991
9360
  );
8992
9361
  const dependencies = platformPackage.dependencies ?? {};
8993
9362
  const platformDependenciesAdded = modules.map((module) => npmPackage(module.package)).filter((packageName) => !(packageName in dependencies)).sort((left, right) => left.localeCompare(right));
@@ -9032,7 +9401,7 @@ async function enableModule(workspace, id, apply) {
9032
9401
  try {
9033
9402
  if (configChanged) {
9034
9403
  const config = JSON.parse(
9035
- await readFile10(workspace.configPath, "utf8")
9404
+ await readFile9(workspace.configPath, "utf8")
9036
9405
  );
9037
9406
  const configModules = config.modules ?? {};
9038
9407
  configModules.enabled = enabled;
@@ -9040,7 +9409,7 @@ async function enableModule(workspace, id, apply) {
9040
9409
  await writeProjectConfig(workspace, config);
9041
9410
  }
9042
9411
  if (platformDependencyAdded) {
9043
- await writeFile4(
9412
+ await writeFile5(
9044
9413
  platformPackagePath,
9045
9414
  JSON.stringify(platformPackage, null, " ") + "\n"
9046
9415
  );
@@ -9114,7 +9483,7 @@ async function disableModule(workspace, id, apply) {
9114
9483
  const enabled = orderedCurrent.filter((module) => module.id !== id).map((module) => module.id);
9115
9484
  const platformPackagePath = join9(workspace.root, "platform/package.json");
9116
9485
  const platformPackage = JSON.parse(
9117
- await readFile10(platformPackagePath, "utf8")
9486
+ await readFile9(platformPackagePath, "utf8")
9118
9487
  );
9119
9488
  const packageName = npmPackage(manifests.get(id).package);
9120
9489
  const dependencyRemoved = Boolean(
@@ -9133,14 +9502,14 @@ async function disableModule(workspace, id, apply) {
9133
9502
  ]);
9134
9503
  try {
9135
9504
  const config = JSON.parse(
9136
- await readFile10(workspace.configPath, "utf8")
9505
+ await readFile9(workspace.configPath, "utf8")
9137
9506
  );
9138
9507
  const modules = config.modules ?? {};
9139
9508
  modules.enabled = enabled;
9140
9509
  config.modules = modules;
9141
9510
  await writeProjectConfig(workspace, config);
9142
9511
  if (dependencyRemoved)
9143
- await writeFile4(
9512
+ await writeFile5(
9144
9513
  platformPackagePath,
9145
9514
  JSON.stringify(platformPackage, null, " ") + "\n"
9146
9515
  );
@@ -9237,7 +9606,7 @@ function planUnmount(workspace, id) {
9237
9606
  }
9238
9607
  async function writeMounts(workspace, mounts) {
9239
9608
  const config = JSON.parse(
9240
- await readFile11(workspace.configPath, "utf8")
9609
+ await readFile10(workspace.configPath, "utf8")
9241
9610
  );
9242
9611
  if (mounts.length === 0) delete config.web;
9243
9612
  else config.web = { ...config.web, mounts };
@@ -9246,8 +9615,8 @@ async function writeMounts(workspace, mounts) {
9246
9615
  }
9247
9616
 
9248
9617
  // src/runner.ts
9249
- import { readFile as readFile24 } from "node:fs/promises";
9250
- import { join as join21, relative as relative14 } from "node:path";
9618
+ import { readFile as readFile22 } from "node:fs/promises";
9619
+ import { join as join20, relative as relative14 } from "node:path";
9251
9620
  import { parse as parseYaml7 } from "yaml";
9252
9621
 
9253
9622
  // src/capabilities.ts
@@ -9481,196 +9850,6 @@ function capability(id) {
9481
9850
  return capabilities.find((entry) => entry.id === id);
9482
9851
  }
9483
9852
 
9484
- // ../database-pglite/src/driver.ts
9485
- import { PGlite } from "@electric-sql/pglite";
9486
- import { mkdir as mkdir5, readFile as readFile12, rm as rm5, writeFile as writeFile5 } from "node:fs/promises";
9487
- import { join as join10 } from "node:path";
9488
- var ROLE = /^[a-z_][a-z0-9_]{0,62}$/;
9489
- var LOCK_FILE = "flowdular.lock";
9490
- var LocalDatabaseLockedError = class extends Error {
9491
- constructor(directory, pid) {
9492
- super(
9493
- `The local database in ${directory} is already open in process ${pid}. Stop that Flowdular first, or point this one at another directory with FD_DATABASE_PGLITE_DIRECTORY.`
9494
- );
9495
- this.directory = directory;
9496
- this.pid = pid;
9497
- this.name = "LocalDatabaseLockedError";
9498
- }
9499
- directory;
9500
- pid;
9501
- code = "LOCAL_DATABASE_LOCKED";
9502
- };
9503
- var LocalDatabaseUnreadableError = class extends Error {
9504
- constructor(directory, cause) {
9505
- super(
9506
- `The local database in ${directory} could not be opened. A process killed mid write leaves it this way. Restore a backup of that directory, recreate the workspace with "pnpm flowdular setup quick --apply --confirm reset-local-auth", or point somewhere else with FD_DATABASE_PGLITE_DIRECTORY.`,
9507
- { cause }
9508
- );
9509
- this.directory = directory;
9510
- this.name = "LocalDatabaseUnreadableError";
9511
- }
9512
- directory;
9513
- code = "LOCAL_DATABASE_UNREADABLE";
9514
- };
9515
- function running(pid) {
9516
- try {
9517
- process.kill(pid, 0);
9518
- return true;
9519
- } catch (error) {
9520
- return error.code === "EPERM";
9521
- }
9522
- }
9523
- async function claimDirectory(directory) {
9524
- const path = join10(directory, LOCK_FILE);
9525
- let held;
9526
- try {
9527
- held = await readFile12(path, "utf8");
9528
- } catch (error) {
9529
- if (error.code !== "ENOENT") throw error;
9530
- }
9531
- const pid = Number(held?.split("\n")[0]);
9532
- if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && running(pid)) {
9533
- throw new LocalDatabaseLockedError(directory, pid);
9534
- }
9535
- await writeFile5(path, `${process.pid}
9536
- ${(/* @__PURE__ */ new Date()).toISOString()}
9537
- `, {
9538
- mode: 384
9539
- });
9540
- }
9541
- async function releaseDirectory(directory) {
9542
- const path = join10(directory, LOCK_FILE);
9543
- try {
9544
- const held = await readFile12(path, "utf8");
9545
- if (Number(held.split("\n")[0]) !== process.pid) return;
9546
- await rm5(path, { force: true });
9547
- } catch (error) {
9548
- const code = error.code;
9549
- if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") return;
9550
- throw error;
9551
- }
9552
- }
9553
- var INT8_OID = 20;
9554
- var SERVER_PARSERS = Object.freeze({ [INT8_OID]: (value) => value });
9555
- var ConnectionQueue = class {
9556
- #tail = Promise.resolve();
9557
- acquire() {
9558
- let release;
9559
- const held = new Promise((resolve9) => {
9560
- release = resolve9;
9561
- });
9562
- const waited = this.#tail.then(() => release);
9563
- this.#tail = this.#tail.then(() => held);
9564
- return waited;
9565
- }
9566
- };
9567
- function result(rows, affected) {
9568
- return {
9569
- rows,
9570
- rowCount: rows.length > 0 ? rows.length : affected
9571
- };
9572
- }
9573
- function createPgliteCluster(options = {}) {
9574
- const queue = new ConnectionQueue();
9575
- let databasePromise;
9576
- let closePromise;
9577
- let issued = 0;
9578
- let ended = 0;
9579
- const close = () => {
9580
- closePromise ??= (async () => {
9581
- if (!databasePromise) return;
9582
- const instance = await databasePromise.catch(() => void 0);
9583
- databasePromise = void 0;
9584
- await instance?.close();
9585
- if (options.dataDirectory) await releaseDirectory(options.dataDirectory);
9586
- })();
9587
- return closePromise;
9588
- };
9589
- const database = async () => {
9590
- databasePromise ??= (async () => {
9591
- const directory = options.dataDirectory;
9592
- if (directory) {
9593
- await mkdir5(directory, { recursive: true, mode: 448 });
9594
- await claimDirectory(directory);
9595
- }
9596
- let created;
9597
- try {
9598
- created = directory ? await PGlite.create({
9599
- dataDir: directory,
9600
- parsers: SERVER_PARSERS
9601
- }) : await PGlite.create({ parsers: SERVER_PARSERS });
9602
- } catch (error) {
9603
- if (!directory) throw error;
9604
- await releaseDirectory(directory);
9605
- throw new LocalDatabaseUnreadableError(directory, error);
9606
- }
9607
- try {
9608
- if (options.bootstrap) await created.exec(options.bootstrap);
9609
- } catch (error) {
9610
- try {
9611
- await created.close();
9612
- } catch (closeError) {
9613
- throw new AggregateError(
9614
- [error, closeError],
9615
- "PGlite bootstrap failed and cleanup also failed."
9616
- );
9617
- }
9618
- throw error;
9619
- }
9620
- return created;
9621
- })();
9622
- return databasePromise;
9623
- };
9624
- const pool = (role) => {
9625
- if (role !== void 0 && !ROLE.test(role)) {
9626
- throw new Error(`"${role}" is not a usable PostgreSQL role name.`);
9627
- }
9628
- issued += 1;
9629
- return {
9630
- cancellation: "before-start",
9631
- async connect() {
9632
- const release = await queue.acquire();
9633
- let instance;
9634
- try {
9635
- instance = await database();
9636
- if (role) await instance.exec(`SET ROLE ${role}`);
9637
- } catch (error) {
9638
- release();
9639
- throw error;
9640
- }
9641
- let released = false;
9642
- const run = async ({
9643
- text,
9644
- values: values2
9645
- }) => {
9646
- if (values2 === void 0 || values2.length === 0) {
9647
- const answers = await instance.exec(text);
9648
- const last = answers[answers.length - 1];
9649
- return last ? result(last.rows, last.affectedRows ?? 0) : result([], 0);
9650
- }
9651
- const answer = await instance.query(text, [...values2]);
9652
- return result(answer.rows, answer.affectedRows ?? 0);
9653
- };
9654
- return {
9655
- query: run,
9656
- release() {
9657
- if (released) return;
9658
- released = true;
9659
- const reset = role ? instance.exec("RESET ROLE").catch(() => void 0) : Promise.resolve();
9660
- void reset.finally(release);
9661
- }
9662
- };
9663
- },
9664
- async end() {
9665
- ended += 1;
9666
- if (ended < issued) return;
9667
- await close();
9668
- }
9669
- };
9670
- };
9671
- return { pool, close };
9672
- }
9673
-
9674
9853
  // src/database.ts
9675
9854
  import { Pool } from "pg";
9676
9855
  function enabledNamespaces(workspace) {
@@ -9762,14 +9941,14 @@ import {
9762
9941
  cp,
9763
9942
  mkdir as mkdir6,
9764
9943
  mkdtemp as mkdtemp2,
9765
- readFile as readFile13,
9944
+ readFile as readFile11,
9766
9945
  readdir as readdir5,
9767
9946
  rename as rename4,
9768
9947
  rm as rm6,
9769
9948
  writeFile as writeFile6
9770
9949
  } from "node:fs/promises";
9771
9950
  import { tmpdir as tmpdir2 } from "node:os";
9772
- import { delimiter, dirname as dirname8, isAbsolute as isAbsolute3, join as join11, resolve as resolve6 } from "node:path";
9951
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute4, join as join10, resolve as resolve8 } from "node:path";
9773
9952
  import { promisify as promisify2 } from "node:util";
9774
9953
  var POSTGRES_DUMP_FILE = "database.dump";
9775
9954
  var PGLITE_PAYLOAD_DIRECTORY = "pglite";
@@ -9797,12 +9976,12 @@ function platformVersion(workspace) {
9797
9976
  return typeof declared === "string" ? declared : "unknown";
9798
9977
  }
9799
9978
  function backupDirectory(workspace, value) {
9800
- return isAbsolute3(value) ? resolve6(value) : resolve6(workspace.root, value);
9979
+ return isAbsolute4(value) ? resolve8(value) : resolve8(workspace.root, value);
9801
9980
  }
9802
9981
  async function resolveTool(name, environment) {
9803
9982
  for (const directory of (environment.PATH ?? "").split(delimiter)) {
9804
9983
  if (!directory) continue;
9805
- const candidate = resolve6(directory, name);
9984
+ const candidate = resolve8(directory, name);
9806
9985
  try {
9807
9986
  await access4(candidate, constants.X_OK);
9808
9987
  return candidate;
@@ -9839,11 +10018,11 @@ async function withPostgresConnection(config, run) {
9839
10018
  "\\n",
9840
10019
  "\n"
9841
10020
  ).trim();
9842
- const temporaryDirectory = !authorityFile && inlineAuthority ? await mkdtemp2(join11(tmpdir2(), "flowdular-backup-")) : void 0;
10021
+ const temporaryDirectory = !authorityFile && inlineAuthority ? await mkdtemp2(join10(tmpdir2(), "flowdular-backup-")) : void 0;
9843
10022
  try {
9844
10023
  let certificate = authorityFile;
9845
10024
  if (temporaryDirectory) {
9846
- certificate = join11(temporaryDirectory, "ca.pem");
10025
+ certificate = join10(temporaryDirectory, "ca.pem");
9847
10026
  await writeFile6(certificate, `${inlineAuthority}
9848
10027
  `, {
9849
10028
  encoding: "utf8",
@@ -9912,7 +10091,7 @@ async function databaseBackup(workspace, output, apply) {
9912
10091
  return failure("DATABASE_CONFIGURATION_INVALID", reason(error));
9913
10092
  }
9914
10093
  const directory = backupDirectory(workspace, output);
9915
- const manifestPath = join11(directory, BACKUP_MANIFEST_FILE);
10094
+ const manifestPath = join10(directory, BACKUP_MANIFEST_FILE);
9916
10095
  if (await exists3(manifestPath)) {
9917
10096
  return failure(
9918
10097
  "BACKUP_TARGET_EXISTS",
@@ -9937,7 +10116,7 @@ async function databaseBackup(workspace, output, apply) {
9937
10116
  "pg_dump was not found on PATH. Install the PostgreSQL client tools matching the server version."
9938
10117
  );
9939
10118
  }
9940
- const payload2 = join11(directory, POSTGRES_DUMP_FILE);
10119
+ const payload2 = join10(directory, POSTGRES_DUMP_FILE);
9941
10120
  const plan2 = {
9942
10121
  adapter: config.adapter,
9943
10122
  applied: apply,
@@ -9975,7 +10154,7 @@ async function databaseBackup(workspace, output, apply) {
9975
10154
  source ? `The embedded database directory ${source} does not exist yet.` : "The embedded database runs in memory under NODE_ENV=test, so there is nothing to copy."
9976
10155
  );
9977
10156
  }
9978
- const payload = join11(directory, PGLITE_PAYLOAD_DIRECTORY);
10157
+ const payload = join10(directory, PGLITE_PAYLOAD_DIRECTORY);
9979
10158
  const plan = {
9980
10159
  adapter: config.adapter,
9981
10160
  applied: apply,
@@ -10002,7 +10181,7 @@ async function databaseBackup(workspace, output, apply) {
10002
10181
  async function restrictTree(root) {
10003
10182
  await chmod(root, 448);
10004
10183
  for (const entry of await readdir5(root, { withFileTypes: true })) {
10005
- const path = join11(root, entry.name);
10184
+ const path = join10(root, entry.name);
10006
10185
  if (entry.isDirectory()) await restrictTree(path);
10007
10186
  else if (entry.isFile()) await chmod(path, 384);
10008
10187
  }
@@ -10013,7 +10192,7 @@ function restoreTarget(config) {
10013
10192
  return decodeURIComponent(url.pathname.slice(1));
10014
10193
  }
10015
10194
  const directory = config.pglite?.dataDirectory;
10016
- return directory === void 0 ? void 0 : resolve6(config.workspaceRoot, directory);
10195
+ return directory === void 0 ? void 0 : resolve8(config.workspaceRoot, directory);
10017
10196
  }
10018
10197
  function describeKeyMismatch(divergent) {
10019
10198
  return divergent.map((key) => `${key.variable} (${key.status})`).join(", ");
@@ -10072,7 +10251,7 @@ function productionRefusal(options, config) {
10072
10251
  );
10073
10252
  }
10074
10253
  const expected = restoreTarget(config);
10075
- const target = config.adapter === "pglite" ? resolve6(config.workspaceRoot, options.target) : options.target;
10254
+ const target = config.adapter === "pglite" ? resolve8(config.workspaceRoot, options.target) : options.target;
10076
10255
  if (target !== expected) {
10077
10256
  return failure(
10078
10257
  "RESTORE_TARGET_MISMATCH",
@@ -10107,11 +10286,11 @@ async function databaseRestore(workspace, input, apply, production) {
10107
10286
  return failure("DATABASE_CONFIGURATION_INVALID", reason(error));
10108
10287
  }
10109
10288
  const directory = backupDirectory(workspace, input);
10110
- const manifestPath = join11(directory, BACKUP_MANIFEST_FILE);
10289
+ const manifestPath = join10(directory, BACKUP_MANIFEST_FILE);
10111
10290
  let manifest2;
10112
10291
  try {
10113
10292
  manifest2 = parseBackupManifest(
10114
- JSON.parse(await readFile13(manifestPath, "utf8"))
10293
+ JSON.parse(await readFile11(manifestPath, "utf8"))
10115
10294
  );
10116
10295
  } catch (error) {
10117
10296
  return error.code === "ENOENT" ? failure(
@@ -10156,7 +10335,7 @@ async function databaseRestore(workspace, input, apply, production) {
10156
10335
  "pg_restore was not found on PATH. Install the PostgreSQL client tools matching the server version."
10157
10336
  );
10158
10337
  }
10159
- const payload2 = join11(directory, POSTGRES_DUMP_FILE);
10338
+ const payload2 = join10(directory, POSTGRES_DUMP_FILE);
10160
10339
  if (!await exists3(payload2)) {
10161
10340
  return failure(
10162
10341
  "BACKUP_PAYLOAD_MISSING",
@@ -10194,7 +10373,7 @@ async function databaseRestore(workspace, input, apply, production) {
10194
10373
  }
10195
10374
  return success(plan2, { evidence: [manifestPath, payload2], warnings });
10196
10375
  }
10197
- const payload = join11(directory, PGLITE_PAYLOAD_DIRECTORY);
10376
+ const payload = join10(directory, PGLITE_PAYLOAD_DIRECTORY);
10198
10377
  if (!await exists3(payload)) {
10199
10378
  return failure(
10200
10379
  "BACKUP_PAYLOAD_MISSING",
@@ -10230,12 +10409,12 @@ async function databaseRestore(workspace, input, apply, production) {
10230
10409
  }
10231
10410
 
10232
10411
  // src/migration-new.ts
10233
- import { readFile as readFile14 } from "node:fs/promises";
10412
+ import { readFile as readFile12 } from "node:fs/promises";
10234
10413
  import { dirname as dirname9 } from "node:path";
10235
10414
 
10236
10415
  // src/migration-scaffold.ts
10237
10416
  import { mkdir as mkdir7, readdir as readdir6, writeFile as writeFile7 } from "node:fs/promises";
10238
- import { join as join12 } from "node:path";
10417
+ import { join as join11 } from "node:path";
10239
10418
  var NAME = /^[a-z][a-z0-9_]{2,48}$/;
10240
10419
  function nextNumber(existing) {
10241
10420
  const highest = existing.filter((entry) => entry.endsWith(".up.sql")).map((entry) => Number.parseInt(entry.slice(0, 4), 10)).filter((value) => Number.isSafeInteger(value)).reduce((left, right) => Math.max(left, right), 0);
@@ -10262,7 +10441,7 @@ async function scaffoldMigration(moduleDirectory, moduleStem, name, apply) {
10262
10441
  `"${name}" must be lowercase letters, digits and underscores, 3 to 49 characters.`
10263
10442
  );
10264
10443
  }
10265
- const directory = join12(moduleDirectory, "migrations");
10444
+ const directory = join11(moduleDirectory, "migrations");
10266
10445
  let existing = [];
10267
10446
  try {
10268
10447
  existing = await readdir6(directory);
@@ -10273,11 +10452,11 @@ async function scaffoldMigration(moduleDirectory, moduleStem, name, apply) {
10273
10452
  const table = `${moduleStem}_${name}`;
10274
10453
  const files = [
10275
10454
  {
10276
- path: join12(directory, `${id}.up.sql`),
10455
+ path: join11(directory, `${id}.up.sql`),
10277
10456
  body: tenantTable(table)
10278
10457
  },
10279
10458
  {
10280
- path: join12(directory, `${id}.down.sql`),
10459
+ path: join11(directory, `${id}.down.sql`),
10281
10460
  body: `DROP POLICY IF EXISTS ${table}_tenant_policy ON ${table};
10282
10461
  DROP INDEX IF EXISTS ${table}_tenant_created_idx;
10283
10462
  DROP TABLE IF EXISTS ${table};
@@ -10298,7 +10477,7 @@ async function migrationScaffold(workspace, moduleId, name, apply) {
10298
10477
  const manifests = await findModuleFiles(workspace);
10299
10478
  for (const manifestPath of manifests) {
10300
10479
  const manifest2 = JSON.parse(
10301
- await readFile14(manifestPath, "utf8")
10480
+ await readFile12(manifestPath, "utf8")
10302
10481
  );
10303
10482
  if (manifest2.id !== moduleId) continue;
10304
10483
  const stem = moduleId.split(".")[0].replaceAll("-", "_");
@@ -10328,8 +10507,8 @@ async function migrationScaffold(workspace, moduleId, name, apply) {
10328
10507
  }
10329
10508
 
10330
10509
  // src/doctor.ts
10331
- import { access as access5, readFile as readFile15 } from "node:fs/promises";
10332
- import { join as join13, relative as relative7 } from "node:path";
10510
+ import { access as access5, readFile as readFile13 } from "node:fs/promises";
10511
+ import { join as join12, relative as relative7 } from "node:path";
10333
10512
  async function exists4(path) {
10334
10513
  try {
10335
10514
  await access5(path);
@@ -10358,20 +10537,20 @@ async function runDoctor(workspace) {
10358
10537
  ["policy.capabilities", agentResource(workspace, "policy")],
10359
10538
  ["policy.model-routing", agentResource(workspace, "modelRouting")],
10360
10539
  ["blueprints.root", agentResource(workspace, "blueprints")],
10361
- ["modules.root", join13(workspace.root, "modules")],
10362
- ...(await sdkModules(workspace)).size ? [] : [["packages.root", join13(workspace.root, "packages")]],
10363
- ["platform.root", join13(workspace.root, "platform")]
10540
+ ["modules.root", join12(workspace.root, "modules")],
10541
+ ...(await sdkModules(workspace)).size ? [] : [["packages.root", join12(workspace.root, "packages")]],
10542
+ ["platform.root", join12(workspace.root, "platform")]
10364
10543
  ]) {
10365
10544
  const path = relative7(workspace.root, resource);
10366
10545
  checks.push({
10367
10546
  id,
10368
- status: await exists4(join13(workspace.root, path)) ? "pass" : "fail",
10369
- message: await exists4(join13(workspace.root, path)) ? `${path} is present.` : `${path} is missing.`,
10547
+ status: await exists4(join12(workspace.root, path)) ? "pass" : "fail",
10548
+ message: await exists4(join12(workspace.root, path)) ? `${path} is present.` : `${path} is missing.`,
10370
10549
  evidence: path
10371
10550
  });
10372
10551
  }
10373
10552
  const packageJson2 = JSON.parse(
10374
- await readFile15(join13(workspace.root, "package.json"), "utf8")
10553
+ await readFile13(join12(workspace.root, "package.json"), "utf8")
10375
10554
  );
10376
10555
  checks.push({
10377
10556
  id: "workspace.pnpm",
@@ -10386,11 +10565,11 @@ async function runDoctor(workspace) {
10386
10565
  message: blueprints.length > 0 ? `${blueprints.length} blueprint(s) discoverable.` : 'No blueprint.json was found; "blueprint validate --all" would pass vacuously.',
10387
10566
  evidence: blueprints.map((file) => relative7(workspace.root, file)).join(", ")
10388
10567
  });
10389
- const entryPath = join13(workspace.root, "platform/src/App.tsrx");
10568
+ const entryPath = join12(workspace.root, "platform/src/App.tsrx");
10390
10569
  if (await exists4(entryPath)) {
10391
- const entry = await readFile15(entryPath, "utf8");
10392
- const pagePath = join13(workspace.root, "platform/index.html");
10393
- const page = await exists4(pagePath) ? await readFile15(pagePath, "utf8") : "";
10570
+ const entry = await readFile13(entryPath, "utf8");
10571
+ const pagePath = join12(workspace.root, "platform/index.html");
10572
+ const page = await exists4(pagePath) ? await readFile13(pagePath, "utf8") : "";
10394
10573
  const renders = entry.includes("configureBrandingFromPage");
10395
10574
  const staticHead = /<meta[^>]+name="theme-color"|<link[^>]+rel="icon"/.test(
10396
10575
  page
@@ -10426,16 +10605,16 @@ async function runDoctor(workspace) {
10426
10605
  import { spawnSync as spawnSync3 } from "node:child_process";
10427
10606
  import { randomUUID as randomUUID5 } from "node:crypto";
10428
10607
  import {
10429
- lstat as lstat6,
10608
+ lstat as lstat5,
10430
10609
  mkdir as mkdir9,
10431
10610
  open as open2,
10432
- readFile as readFile17,
10611
+ readFile as readFile15,
10433
10612
  realpath as realpath2,
10434
10613
  rename as rename6,
10435
10614
  rm as rm8,
10436
10615
  writeFile as writeFile9
10437
10616
  } from "node:fs/promises";
10438
- import { isAbsolute as isAbsolute4, join as join15, relative as relative9 } from "node:path";
10617
+ import { isAbsolute as isAbsolute5, join as join14, relative as relative9 } from "node:path";
10439
10618
  import { parse as parseYaml5 } from "yaml";
10440
10619
 
10441
10620
  // src/vercel-launch.ts
@@ -10444,17 +10623,17 @@ import { createHash as createHash6, randomBytes as randomBytes2, randomUUID as r
10444
10623
  import {
10445
10624
  chmod as chmod2,
10446
10625
  copyFile,
10447
- lstat as lstat5,
10626
+ lstat as lstat4,
10448
10627
  mkdir as mkdir8,
10449
10628
  mkdtemp as mkdtemp3,
10450
10629
  open,
10451
- readFile as readFile16,
10630
+ readFile as readFile14,
10452
10631
  rename as rename5,
10453
10632
  rm as rm7,
10454
10633
  writeFile as writeFile8
10455
10634
  } from "node:fs/promises";
10456
10635
  import { tmpdir as tmpdir3 } from "node:os";
10457
- import { dirname as dirname10, join as join14, relative as relative8 } from "node:path";
10636
+ import { dirname as dirname10, join as join13, relative as relative8 } from "node:path";
10458
10637
  import { Client } from "pg";
10459
10638
 
10460
10639
  // src/database-roles.ts
@@ -10699,7 +10878,7 @@ ${run.stdout}`.split("\n").map((line) => line.trim()).filter(Boolean);
10699
10878
  }
10700
10879
  function runVercel(context, args, mode = {}) {
10701
10880
  const fullArgs = context.options.scope ? [...args, "--scope", context.options.scope] : [...args];
10702
- return new Promise((resolve9, reject) => {
10881
+ return new Promise((resolve11, reject) => {
10703
10882
  const child = spawn("vercel", fullArgs, {
10704
10883
  cwd: mode.cwd ?? context.root,
10705
10884
  stdio: mode.interactive ? "inherit" : [mode.input === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
@@ -10726,7 +10905,7 @@ function runVercel(context, args, mode = {}) {
10726
10905
  if (rest) process.stderr.write(`${redact(context, rest)}
10727
10906
  `);
10728
10907
  }
10729
- resolve9({ status: code ?? 1, ...captured });
10908
+ resolve11({ status: code ?? 1, ...captured });
10730
10909
  });
10731
10910
  });
10732
10911
  }
@@ -10737,17 +10916,17 @@ function unexpected(command) {
10737
10916
  );
10738
10917
  }
10739
10918
  async function readProjectLink(root) {
10740
- const path = join14(root, ".vercel/project.json");
10919
+ const path = join13(root, ".vercel/project.json");
10741
10920
  let link;
10742
10921
  try {
10743
- const entry = await lstat5(path);
10922
+ const entry = await lstat4(path);
10744
10923
  if (!entry.isFile() || entry.size > 16 * 1024) {
10745
10924
  throw new LaunchError(
10746
10925
  "VERCEL_LINK_INVALID",
10747
10926
  ".vercel/project.json must be a regular file. Remove .vercel and rerun to link again."
10748
10927
  );
10749
10928
  }
10750
- link = JSON.parse(await readFile16(path, "utf8"));
10929
+ link = JSON.parse(await readFile14(path, "utf8"));
10751
10930
  } catch (error) {
10752
10931
  if (error.code === "ENOENT") return null;
10753
10932
  if (error instanceof LaunchError) throw error;
@@ -10834,14 +11013,14 @@ async function setProductionVariable(context, name, value, exists5) {
10834
11013
  }
10835
11014
  async function readPrivateFile(root, path, maxKiB, code) {
10836
11015
  try {
10837
- const entry = await lstat5(path);
11016
+ const entry = await lstat4(path);
10838
11017
  if (!entry.isFile() || entry.size > maxKiB * 1024) {
10839
11018
  throw new LaunchError(
10840
11019
  code,
10841
11020
  `${relative8(root, path)} must be a regular file of at most ${maxKiB} KiB.`
10842
11021
  );
10843
11022
  }
10844
- const text = await readFile16(path, "utf8");
11023
+ const text = await readFile14(path, "utf8");
10845
11024
  await chmod2(path, 384);
10846
11025
  return text;
10847
11026
  } catch (error) {
@@ -10850,7 +11029,7 @@ async function readPrivateFile(root, path, maxKiB, code) {
10850
11029
  }
10851
11030
  }
10852
11031
  async function readKeyBackup(root, project) {
10853
- const path = join14(root, ".flowdular/deploy", `vercel-${project.id}.env`);
11032
+ const path = join13(root, ".flowdular/deploy", `vercel-${project.id}.env`);
10854
11033
  const values2 = /* @__PURE__ */ new Map();
10855
11034
  const text = await readPrivateFile(root, path, 64, "KEY_BACKUP_INVALID");
10856
11035
  for (const line of text?.split("\n") ?? []) {
@@ -10874,8 +11053,8 @@ async function writeKeyBackup(root, project, backup) {
10874
11053
  async function writePrivateFile(root, path, contents) {
10875
11054
  const directory = dirname10(path);
10876
11055
  await mkdir8(directory, { recursive: true, mode: 448 });
10877
- for (const path2 of [join14(root, ".flowdular"), directory]) {
10878
- if (!(await lstat5(path2)).isDirectory()) {
11056
+ for (const path2 of [join13(root, ".flowdular"), directory]) {
11057
+ if (!(await lstat4(path2)).isDirectory()) {
10879
11058
  throw new LaunchError(
10880
11059
  "KEY_BACKUP_INVALID",
10881
11060
  `${relative8(root, path2)} must be a directory inside the workspace.`
@@ -10898,7 +11077,7 @@ async function writePrivateFile(root, path, contents) {
10898
11077
  }
10899
11078
  }
10900
11079
  function setupTokenPath(root, project) {
10901
- return join14(root, ".flowdular/deploy", `vercel-${project.id}.setup-token`);
11080
+ return join13(root, ".flowdular/deploy", `vercel-${project.id}.setup-token`);
10902
11081
  }
10903
11082
  async function saveSetupToken(context, project) {
10904
11083
  const path = setupTokenPath(context.root, project);
@@ -10971,9 +11150,9 @@ function roleUrl(owner, role, password) {
10971
11150
  return `postgresql://${encodeURIComponent(APPLICATION_ROLES[role])}:${encodeURIComponent(password)}@${owner.host}${owner.pathname}`;
10972
11151
  }
10973
11152
  async function pullProductionValue(context, name) {
10974
- const directory = await mkdtemp3(join14(tmpdir3(), "flowdular-vercel-env-"));
11153
+ const directory = await mkdtemp3(join13(tmpdir3(), "flowdular-vercel-env-"));
10975
11154
  try {
10976
- const file = join14(directory, "production.env");
11155
+ const file = join13(directory, "production.env");
10977
11156
  await writeFile8(file, "", { mode: 384, flag: "wx" });
10978
11157
  const run = await runVercel(context, [
10979
11158
  "env",
@@ -10990,7 +11169,7 @@ async function pullProductionValue(context, name) {
10990
11169
  );
10991
11170
  }
10992
11171
  const prefix = `${name}="`;
10993
- const line = (await readFile16(file, "utf8")).split("\n").find((entry) => entry.startsWith(prefix) && entry.endsWith('"'));
11172
+ const line = (await readFile14(file, "utf8")).split("\n").find((entry) => entry.startsWith(prefix) && entry.endsWith('"'));
10994
11173
  const value = line?.slice(prefix.length, -1);
10995
11174
  return value && value !== "[SENSITIVE]" ? remember(context, value) : void 0;
10996
11175
  } finally {
@@ -10999,12 +11178,12 @@ async function pullProductionValue(context, name) {
10999
11178
  }
11000
11179
  async function provisionNeon(context) {
11001
11180
  progress("Provisioning Neon PostgreSQL through the Vercel Marketplace");
11002
- const directory = await mkdtemp3(join14(tmpdir3(), "flowdular-vercel-neon-"));
11181
+ const directory = await mkdtemp3(join13(tmpdir3(), "flowdular-vercel-neon-"));
11003
11182
  try {
11004
- await mkdir8(join14(directory, ".vercel"), { mode: 448 });
11183
+ await mkdir8(join13(directory, ".vercel"), { mode: 448 });
11005
11184
  await copyFile(
11006
- join14(context.root, ".vercel/project.json"),
11007
- join14(directory, ".vercel/project.json")
11185
+ join13(context.root, ".vercel/project.json"),
11186
+ join13(directory, ".vercel/project.json")
11008
11187
  );
11009
11188
  const run = await runVercel(
11010
11189
  context,
@@ -11519,6 +11698,8 @@ function defaultVercelHost() {
11519
11698
  application_name: "flowdular-deploy",
11520
11699
  connectionTimeoutMillis: 15e3
11521
11700
  });
11701
+ client.on("error", () => {
11702
+ });
11522
11703
  await client.connect();
11523
11704
  return {
11524
11705
  query: (text) => client.query(text),
@@ -11534,7 +11715,7 @@ function defaultVercelHost() {
11534
11715
  )
11535
11716
  );
11536
11717
  }
11537
- return new Promise((resolve9, reject) => {
11718
+ return new Promise((resolve11, reject) => {
11538
11719
  const child = spawn(
11539
11720
  process.execPath,
11540
11721
  [...process.execArgv, entry, ...args, "--json"],
@@ -11550,7 +11731,7 @@ function defaultVercelHost() {
11550
11731
  child.once("error", reject);
11551
11732
  child.once("close", () => {
11552
11733
  try {
11553
- resolve9(JSON.parse(stdout));
11734
+ resolve11(JSON.parse(stdout));
11554
11735
  } catch {
11555
11736
  reject(
11556
11737
  new Error("The flowdular child command printed no envelope.")
@@ -11560,7 +11741,7 @@ function defaultVercelHost() {
11560
11741
  });
11561
11742
  },
11562
11743
  fetch: (url, init) => fetch(url, init),
11563
- wait: (ms) => new Promise((resolve9) => setTimeout(resolve9, ms))
11744
+ wait: (ms) => new Promise((resolve11) => setTimeout(resolve11, ms))
11564
11745
  };
11565
11746
  }
11566
11747
 
@@ -11604,23 +11785,23 @@ var deploymentAdapters = [
11604
11785
  ];
11605
11786
  var DEPLOYMENT_HISTORY_LIMIT = 64;
11606
11787
  async function recordDeployment(root, record) {
11607
- const directory = join15(root, ".flowdular");
11788
+ const directory = join14(root, ".flowdular");
11608
11789
  await mkdir9(directory, { recursive: true, mode: 448 });
11609
- if (!(await lstat6(directory)).isDirectory()) {
11790
+ if (!(await lstat5(directory)).isDirectory()) {
11610
11791
  throw new Error(
11611
11792
  "Deployment audit directory must be a directory inside the workspace."
11612
11793
  );
11613
11794
  }
11614
- const path = join15(directory, "deployments.json");
11795
+ const path = join14(directory, "deployments.json");
11615
11796
  let history = [];
11616
11797
  try {
11617
- const entry = await lstat6(path);
11798
+ const entry = await lstat5(path);
11618
11799
  if (!entry.isFile() || entry.size > 128 * 1024) {
11619
11800
  throw new Error(
11620
11801
  "Deployment audit journal is not a bounded regular file."
11621
11802
  );
11622
11803
  }
11623
- history = JSON.parse(await readFile17(path, "utf8"));
11804
+ history = JSON.parse(await readFile15(path, "utf8"));
11624
11805
  if (!Array.isArray(history))
11625
11806
  throw new Error("Deployment audit journal is invalid.");
11626
11807
  } catch (error) {
@@ -11645,12 +11826,12 @@ async function recordDeployment(root, record) {
11645
11826
  }
11646
11827
  async function workspaceFile(root, path) {
11647
11828
  try {
11648
- const file = join15(root, path);
11649
- if (!(await lstat6(file)).isFile()) return false;
11829
+ const file = join14(root, path);
11830
+ if (!(await lstat5(file)).isFile()) return false;
11650
11831
  const canonicalRoot = await realpath2(root);
11651
11832
  const canonicalFile = await realpath2(file);
11652
11833
  const pathFromRoot = relative9(canonicalRoot, canonicalFile);
11653
- return pathFromRoot !== "" && !pathFromRoot.startsWith("..") && !isAbsolute4(pathFromRoot);
11834
+ return pathFromRoot !== "" && !pathFromRoot.startsWith("..") && !isAbsolute5(pathFromRoot);
11654
11835
  } catch {
11655
11836
  return false;
11656
11837
  }
@@ -11682,9 +11863,9 @@ async function renderBlueprintIssue(root) {
11682
11863
  return "render.yaml must be a regular file at the repository root.";
11683
11864
  let blueprint;
11684
11865
  try {
11685
- if ((await lstat6(join15(root, path))).size > 128 * 1024)
11866
+ if ((await lstat5(join14(root, path))).size > 128 * 1024)
11686
11867
  return "render.yaml exceeds the 128 KiB preflight limit.";
11687
- blueprint = parseYaml5(await readFile17(join15(root, path), "utf8"));
11868
+ blueprint = parseYaml5(await readFile15(join14(root, path), "utf8"));
11688
11869
  } catch {
11689
11870
  return "render.yaml must contain valid YAML.";
11690
11871
  }
@@ -11840,10 +12021,10 @@ async function vercelArtifactIssue(root) {
11840
12021
  }
11841
12022
  let config;
11842
12023
  try {
11843
- const path = join15(root, "vercel.json");
11844
- if ((await lstat6(path)).size > 16 * 1024)
12024
+ const path = join14(root, "vercel.json");
12025
+ if ((await lstat5(path)).size > 16 * 1024)
11845
12026
  return "vercel.json exceeds the 16 KiB preflight limit.";
11846
- config = JSON.parse(await readFile17(path, "utf8"));
12027
+ config = JSON.parse(await readFile15(path, "utf8"));
11847
12028
  } catch {
11848
12029
  return "vercel.json must contain valid JSON.";
11849
12030
  }
@@ -11852,15 +12033,15 @@ async function vercelArtifactIssue(root) {
11852
12033
  return null;
11853
12034
  }
11854
12035
  async function vercelUploadIgnoreIssue(root) {
11855
- const path = join15(root, ".vercelignore");
12036
+ const path = join14(root, ".vercelignore");
11856
12037
  if (!await workspaceFile(root, ".vercelignore"))
11857
12038
  return ".vercelignore must exist so vercel deploy does not upload .env files or the key backup under .flowdular.";
11858
12039
  let patterns;
11859
12040
  try {
11860
- if ((await lstat6(path)).size > 16 * 1024)
12041
+ if ((await lstat5(path)).size > 16 * 1024)
11861
12042
  return ".vercelignore exceeds the 16 KiB preflight limit.";
11862
12043
  patterns = new Set(
11863
- (await readFile17(path, "utf8")).split("\n").map((line) => line.trim().replace(/^\*\*\//, ""))
12044
+ (await readFile15(path, "utf8")).split("\n").map((line) => line.trim().replace(/^\*\*\//, ""))
11864
12045
  );
11865
12046
  } catch {
11866
12047
  return ".vercelignore must be readable.";
@@ -12032,15 +12213,15 @@ async function runDeployment(workspace, action, target, arguments_, terminal = {
12032
12213
  }
12033
12214
  );
12034
12215
  }
12035
- const directory = join15(workspace.root, ".flowdular");
12216
+ const directory = join14(workspace.root, ".flowdular");
12036
12217
  await mkdir9(directory, { recursive: true, mode: 448 });
12037
- if (!(await lstat6(directory)).isDirectory()) {
12218
+ if (!(await lstat5(directory)).isDirectory()) {
12038
12219
  return failure(
12039
12220
  "DEPLOY_AUDIT_FAILED",
12040
12221
  "The local audit directory is invalid."
12041
12222
  );
12042
12223
  }
12043
- const lockPath = join15(directory, "deployment.lock");
12224
+ const lockPath = join14(directory, "deployment.lock");
12044
12225
  let lock;
12045
12226
  try {
12046
12227
  lock = await open2(lockPath, "wx", 384);
@@ -12082,7 +12263,7 @@ async function launchDocker(workspace, arguments_, record) {
12082
12263
  );
12083
12264
  const result2 = spawnSync3(
12084
12265
  process.execPath,
12085
- [join15(workspace.root, "infra/docker/start.mjs"), ...flags],
12266
+ [join14(workspace.root, "infra/docker/start.mjs"), ...flags],
12086
12267
  {
12087
12268
  cwd: workspace.root,
12088
12269
  stdio: "inherit"
@@ -12111,13 +12292,13 @@ async function launchDocker(workspace, arguments_, record) {
12111
12292
  }
12112
12293
 
12113
12294
  // src/extensions.ts
12114
- import { readFile as readFile18 } from "node:fs/promises";
12295
+ import { readFile as readFile16 } from "node:fs/promises";
12115
12296
  import { dirname as dirname12, relative as relative10 } from "node:path";
12116
12297
 
12117
12298
  // src/module-import.ts
12118
- import { readFileSync as readFileSync2, realpathSync } from "node:fs";
12299
+ import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
12119
12300
  import {
12120
- createRequire as createRequire4,
12301
+ createRequire as createRequire3,
12121
12302
  registerHooks,
12122
12303
  stripTypeScriptTypes
12123
12304
  } from "node:module";
@@ -12126,11 +12307,11 @@ import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "node:url";
12126
12307
  var roots = /* @__PURE__ */ new Set();
12127
12308
  var registered = false;
12128
12309
  async function importModuleSource(entry, moduleRoot) {
12129
- roots.add(realpathSync(moduleRoot));
12310
+ roots.add(realpathSync2(moduleRoot));
12130
12311
  try {
12131
- const require2 = createRequire4(pathToFileURL2(entry));
12312
+ const require2 = createRequire3(pathToFileURL2(entry));
12132
12313
  roots.add(
12133
- realpathSync(dirname11(require2.resolve("@flowdular/sdk/package.json")))
12314
+ realpathSync2(dirname11(require2.resolve("@flowdular/sdk/package.json")))
12134
12315
  );
12135
12316
  } catch (error) {
12136
12317
  if (!["MODULE_NOT_FOUND", "ERR_PACKAGE_PATH_NOT_EXPORTED"].includes(
@@ -12143,12 +12324,12 @@ async function importModuleSource(entry, moduleRoot) {
12143
12324
  load(url, context, nextLoad) {
12144
12325
  if (!url.startsWith("file:") || !fileURLToPath(url).endsWith(".ts"))
12145
12326
  return nextLoad(url, context);
12146
- const path = realpathSync(fileURLToPath(url));
12327
+ const path = realpathSync2(fileURLToPath(url));
12147
12328
  if (![...roots].some((root) => path.startsWith(root + sep2)))
12148
12329
  return nextLoad(url, context);
12149
12330
  return {
12150
12331
  format: "module",
12151
- source: stripTypeScriptTypes(readFileSync2(path, "utf8"), {
12332
+ source: stripTypeScriptTypes(readFileSync3(path, "utf8"), {
12152
12333
  mode: "transform",
12153
12334
  sourceUrl: url
12154
12335
  }),
@@ -12252,7 +12433,7 @@ async function loadCliExtensions(workspace) {
12252
12433
  const loaded = [];
12253
12434
  for (const manifestPath of manifests) {
12254
12435
  const manifest2 = JSON.parse(
12255
- await readFile18(manifestPath, "utf8")
12436
+ await readFile16(manifestPath, "utf8")
12256
12437
  );
12257
12438
  if (!enabled.has(manifest2.id) || !manifest2.cli) continue;
12258
12439
  const moduleRoot = dirname12(manifestPath);
@@ -12268,7 +12449,7 @@ async function loadCliExtensions(workspace) {
12268
12449
  );
12269
12450
  }
12270
12451
  const catalog = JSON.parse(
12271
- await readFile18(catalogPath, "utf8")
12452
+ await readFile16(catalogPath, "utf8")
12272
12453
  );
12273
12454
  validateCliCatalog(catalog, manifest2);
12274
12455
  for (const command of catalog.commands) {
@@ -12292,12 +12473,12 @@ async function loadCliExtensions(workspace) {
12292
12473
  }
12293
12474
 
12294
12475
  // src/migration.ts
12295
- import { readFile as readFile20, stat as stat2 } from "node:fs/promises";
12296
- import { dirname as dirname13, join as join17 } from "node:path";
12476
+ import { readFile as readFile18, stat as stat2 } from "node:fs/promises";
12477
+ import { dirname as dirname13, join as join16 } from "node:path";
12297
12478
 
12298
12479
  // src/migration-audit.ts
12299
- import { readdir as readdir7, readFile as readFile19 } from "node:fs/promises";
12300
- import { join as join16 } from "node:path";
12480
+ import { readdir as readdir7, readFile as readFile17 } from "node:fs/promises";
12481
+ import { join as join15 } from "node:path";
12301
12482
  function statementsOf2(sql) {
12302
12483
  return sql.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*\n/g, "\n");
12303
12484
  }
@@ -12368,13 +12549,13 @@ async function scripts(directory) {
12368
12549
  for (const entry of entries.filter((name) => name.endsWith(".up.sql"))) {
12369
12550
  found.set(
12370
12551
  entry.slice(0, -".up.sql".length),
12371
- await readFile19(join16(directory, entry), "utf8")
12552
+ await readFile17(join15(directory, entry), "utf8")
12372
12553
  );
12373
12554
  }
12374
12555
  return found;
12375
12556
  }
12376
12557
  async function moduleMigrationAudit(moduleId, moduleDirectory, declared) {
12377
- const found = await scripts(join16(moduleDirectory, "migrations"));
12558
+ const found = await scripts(join15(moduleDirectory, "migrations"));
12378
12559
  const issues = [];
12379
12560
  const declaredIds = new Set(declared.map((migration) => migration.id));
12380
12561
  for (const migrationId of [...declaredIds].sort()) {
@@ -12458,11 +12639,11 @@ async function loadMigrationModules(workspace, moduleId) {
12458
12639
  const unmanaged = [];
12459
12640
  for (const manifestPath of manifests) {
12460
12641
  const manifest2 = JSON.parse(
12461
- await readFile20(manifestPath, "utf8")
12642
+ await readFile18(manifestPath, "utf8")
12462
12643
  );
12463
12644
  if (!enabled.has(manifest2.id)) continue;
12464
12645
  if (moduleId && manifest2.id !== moduleId) continue;
12465
- const entry = join17(dirname13(manifestPath), "src/services/migration.ts");
12646
+ const entry = join16(dirname13(manifestPath), "src/services/migration.ts");
12466
12647
  try {
12467
12648
  await stat2(entry);
12468
12649
  } catch (error) {
@@ -12704,12 +12885,12 @@ import {
12704
12885
  access as access6,
12705
12886
  mkdir as mkdir10,
12706
12887
  readdir as readdir8,
12707
- readFile as readFile21,
12888
+ readFile as readFile19,
12708
12889
  realpath as realpath3,
12709
12890
  rm as rm9,
12710
12891
  writeFile as writeFile10
12711
12892
  } from "node:fs/promises";
12712
- import { dirname as dirname14, join as join18, relative as relative11, resolve as resolve7 } from "node:path";
12893
+ import { dirname as dirname14, join as join17, relative as relative11, resolve as resolve9 } from "node:path";
12713
12894
  import { parse as parseYaml6 } from "yaml";
12714
12895
  var IGNORED_ENTRIES = /* @__PURE__ */ new Set(["node_modules", "dist"]);
12715
12896
  function ownedByAuthor(path) {
@@ -12719,7 +12900,7 @@ async function listFiles(directory) {
12719
12900
  const files = [];
12720
12901
  for (const entry of await readdir8(directory, { withFileTypes: true })) {
12721
12902
  if (IGNORED_ENTRIES.has(entry.name)) continue;
12722
- const path = join18(directory, entry.name);
12903
+ const path = join17(directory, entry.name);
12723
12904
  if (entry.isDirectory()) files.push(...await listFiles(path));
12724
12905
  else files.push(path);
12725
12906
  }
@@ -12746,9 +12927,9 @@ async function inspectTarget(workspaceRoot, moduleDirectory, specPath, specSourc
12746
12927
  );
12747
12928
  }
12748
12929
  if (present.has("spec/module.yaml")) {
12749
- const existingSpecPath = join18(moduleDirectory, "spec/module.yaml");
12750
- const sameFile = resolve7(specPath) === await realpath3(existingSpecPath);
12751
- if (!sameFile && await readFile21(existingSpecPath, "utf8") !== specSource) {
12930
+ const existingSpecPath = join17(moduleDirectory, "spec/module.yaml");
12931
+ const sameFile = resolve9(specPath) === await realpath3(existingSpecPath);
12932
+ if (!sameFile && await readFile19(existingSpecPath, "utf8") !== specSource) {
12752
12933
  throw new Error(
12753
12934
  `${relative11(workspaceRoot, existingSpecPath)} holds a different specification than ${relative11(workspaceRoot, specPath)}.`
12754
12935
  );
@@ -12762,7 +12943,7 @@ async function writeScaffold(moduleDirectory, files, target) {
12762
12943
  try {
12763
12944
  for (const [path, source] of files) {
12764
12945
  if (target.present.has(path)) continue;
12765
- const absolute = join18(moduleDirectory, path);
12946
+ const absolute = join17(moduleDirectory, path);
12766
12947
  const created = await mkdir10(dirname14(absolute), { recursive: true });
12767
12948
  if (created) createdDirectories.push(created);
12768
12949
  await writeFile10(absolute, source, { encoding: "utf8", flag: "wx" });
@@ -12796,7 +12977,7 @@ async function scaffoldModule(workspace, request) {
12796
12977
  `Module specification is invalid: ${specReport.issues.filter((issue2) => issue2.severity === "error").map((issue2) => issue2.message).join("; ")}`
12797
12978
  );
12798
12979
  }
12799
- const specSource = await readFile21(specPath, "utf8");
12980
+ const specSource = await readFile19(specPath, "utf8");
12800
12981
  const spec = parseYaml6(specSource);
12801
12982
  if (spec.id !== request.id)
12802
12983
  throw new Error(
@@ -12808,7 +12989,7 @@ async function scaffoldModule(workspace, request) {
12808
12989
  );
12809
12990
  const existingManifests = (await findNamedFiles(workspace.root, "module.json")).filter((path) => path.includes("/modules/"));
12810
12991
  for (const path of existingManifests) {
12811
- const existing = JSON.parse(await readFile21(path, "utf8"));
12992
+ const existing = JSON.parse(await readFile19(path, "utf8"));
12812
12993
  if (existing.id === request.id) {
12813
12994
  throw new Error(
12814
12995
  `Module id "${request.id}" is already registered by ${relative11(workspace.root, path)}.`
@@ -12817,7 +12998,7 @@ async function scaffoldModule(workspace, request) {
12817
12998
  }
12818
12999
  const moduleDirectory = resolveInside(
12819
13000
  workspace.root,
12820
- join18("modules", packageSuffix(request.id))
13001
+ join17("modules", packageSuffix(request.id))
12821
13002
  );
12822
13003
  const target = await inspectTarget(
12823
13004
  workspace.root,
@@ -12839,8 +13020,8 @@ async function scaffoldModule(workspace, request) {
12839
13020
  applied: request.apply,
12840
13021
  formatted,
12841
13022
  moduleDirectory: moduleRelative,
12842
- files: [...planned.keys()].map((path) => join18(moduleRelative, path)),
12843
- skipped: [...planned.keys()].filter((path) => target.present.has(path)).map((path) => join18(moduleRelative, path))
13023
+ files: [...planned.keys()].map((path) => join17(moduleRelative, path)),
13024
+ skipped: [...planned.keys()].filter((path) => target.present.has(path)).map((path) => join17(moduleRelative, path))
12844
13025
  };
12845
13026
  }
12846
13027
  async function formatFiles(moduleDirectory, files, formatter) {
@@ -12848,7 +13029,7 @@ async function formatFiles(moduleDirectory, files, formatter) {
12848
13029
  for (const [path, source] of files) {
12849
13030
  formatted.set(
12850
13031
  path,
12851
- await formatter.format(join18(moduleDirectory, path), source)
13032
+ await formatter.format(join17(moduleDirectory, path), source)
12852
13033
  );
12853
13034
  }
12854
13035
  return formatted;
@@ -12859,20 +13040,15 @@ import { constants as constants2 } from "node:fs";
12859
13040
  import {
12860
13041
  chmod as chmod3,
12861
13042
  copyFile as copyFile2,
12862
- lstat as lstat7,
13043
+ lstat as lstat6,
12863
13044
  mkdir as mkdir11,
12864
13045
  readdir as readdir9,
12865
- readFile as readFile22,
13046
+ readFile as readFile20,
12866
13047
  rm as rm10,
12867
13048
  stat as stat3
12868
13049
  } from "node:fs/promises";
12869
- import { dirname as dirname15, join as join19, relative as relative12 } from "node:path";
13050
+ import { dirname as dirname15, join as join18, relative as relative12 } from "node:path";
12870
13051
  import { createHash as createHash7 } from "node:crypto";
12871
-
12872
- // ../kernel/src/legacy-local-state.ts
12873
- var LEGACY_DATA_DIRECTORY = ".octane-erp";
12874
-
12875
- // src/state-migration.ts
12876
13052
  var STATE_FILES = [
12877
13053
  "agent-credential.key",
12878
13054
  "agent-run-grant.key",
@@ -12886,7 +13062,7 @@ function isMissing(error) {
12886
13062
  }
12887
13063
  async function pathState(path) {
12888
13064
  try {
12889
- return await lstat7(path);
13065
+ return await lstat6(path);
12890
13066
  } catch (error) {
12891
13067
  if (isMissing(error)) return void 0;
12892
13068
  throw error;
@@ -12896,9 +13072,9 @@ function relativePath(workspace, path) {
12896
13072
  return relative12(workspace.root, path);
12897
13073
  }
12898
13074
  async function migrationPlan(workspace) {
12899
- const sourceDirectory = join19(workspace.root, LEGACY_DATA_DIRECTORY);
13075
+ const sourceDirectory = join18(workspace.root, LEGACY_DATA_DIRECTORY);
12900
13076
  const stateDirectory = flowdularStateDirectory(workspace.root);
12901
- const destinationDirectory = join19(stateDirectory, "data");
13077
+ const destinationDirectory = join18(stateDirectory, "data");
12902
13078
  const destinationLabel = relativePath(workspace, destinationDirectory);
12903
13079
  const blockers = [];
12904
13080
  const missing = [];
@@ -12936,8 +13112,8 @@ async function migrationPlan(workspace) {
12936
13112
  if (isLegacyDatabase(name)) unsupported.push(name);
12937
13113
  }
12938
13114
  for (const name of STATE_FILES) {
12939
- const source = join19(sourceDirectory, name);
12940
- const destination = join19(destinationDirectory, name);
13115
+ const source = join18(sourceDirectory, name);
13116
+ const destination = join18(destinationDirectory, name);
12941
13117
  const sourceFile = await pathState(source);
12942
13118
  if (!sourceFile) {
12943
13119
  missing.push(name);
@@ -12963,7 +13139,7 @@ async function migrationPlan(workspace) {
12963
13139
  };
12964
13140
  }
12965
13141
  async function digest(path) {
12966
- return createHash7("sha256").update(await readFile22(path)).digest("hex");
13142
+ return createHash7("sha256").update(await readFile20(path)).digest("hex");
12967
13143
  }
12968
13144
  async function ensurePrivateDirectory(path) {
12969
13145
  try {
@@ -12972,7 +13148,7 @@ async function ensurePrivateDirectory(path) {
12972
13148
  if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
12973
13149
  throw error;
12974
13150
  }
12975
- const state = await lstat7(path);
13151
+ const state = await lstat6(path);
12976
13152
  if (state.isSymbolicLink() || !state.isDirectory()) {
12977
13153
  throw new Error(`${path} is not a safe local state directory.`);
12978
13154
  }
@@ -12984,7 +13160,7 @@ async function copyPlan(plan) {
12984
13160
  const created = [];
12985
13161
  try {
12986
13162
  for (const file of plan.files) {
12987
- const sourceState = await lstat7(file.source);
13163
+ const sourceState = await lstat6(file.source);
12988
13164
  if (sourceState.isSymbolicLink() || !sourceState.isFile()) {
12989
13165
  throw new Error(`${file.name} is no longer a regular file.`);
12990
13166
  }
@@ -13064,7 +13240,7 @@ async function migrateLegacyState(workspace, apply) {
13064
13240
  }
13065
13241
  return success(data(plan, true), {
13066
13242
  evidence: plan.files.map(
13067
- (file) => relativePath(workspace, join19(plan.destinationDirectory, file.name))
13243
+ (file) => relativePath(workspace, join18(plan.destinationDirectory, file.name))
13068
13244
  ),
13069
13245
  warnings: [
13070
13246
  ...unsupportedWarnings(plan),
@@ -13074,8 +13250,8 @@ async function migrateLegacyState(workspace, apply) {
13074
13250
  }
13075
13251
 
13076
13252
  // src/module-version.ts
13077
- import { readFile as readFile23, writeFile as writeFile11 } from "node:fs/promises";
13078
- import { dirname as dirname16, join as join20, relative as relative13 } from "node:path";
13253
+ import { readFile as readFile21, writeFile as writeFile11 } from "node:fs/promises";
13254
+ import { dirname as dirname16, join as join19, relative as relative13 } from "node:path";
13079
13255
  var LOCK2 = "flowdular.modules.lock.json";
13080
13256
  var LEVELS = ["patch", "minor", "major"];
13081
13257
  function specDirectory(workspace) {
@@ -13085,7 +13261,7 @@ function specDirectory(workspace) {
13085
13261
  async function loadModules(workspace) {
13086
13262
  const modules = [];
13087
13263
  for (const file of await findModuleFiles(workspace)) {
13088
- const manifest2 = JSON.parse(await readFile23(file, "utf8"));
13264
+ const manifest2 = JSON.parse(await readFile21(file, "utf8"));
13089
13265
  modules.push({ file, root: dirname16(file), manifest: manifest2 });
13090
13266
  }
13091
13267
  return modules;
@@ -13093,7 +13269,7 @@ async function loadModules(workspace) {
13093
13269
  async function installerManaged(workspace, id) {
13094
13270
  try {
13095
13271
  const lock = JSON.parse(
13096
- await readFile23(join20(workspace.root, LOCK2), "utf8")
13272
+ await readFile21(join19(workspace.root, LOCK2), "utf8")
13097
13273
  );
13098
13274
  return (lock.modules ?? []).some((entry) => entry.id === id);
13099
13275
  } catch (error) {
@@ -13136,7 +13312,7 @@ function specRangeEdit(source, id, range) {
13136
13312
  }
13137
13313
  async function readOptional(path) {
13138
13314
  try {
13139
- return await readFile23(path, "utf8");
13315
+ return await readFile21(path, "utf8");
13140
13316
  } catch (error) {
13141
13317
  if (error.code === "ENOENT") return null;
13142
13318
  throw error;
@@ -13168,7 +13344,7 @@ async function bumpModuleVersion(workspace, options) {
13168
13344
  const files = [];
13169
13345
  const manual = [];
13170
13346
  const rel = (path) => relative13(workspace.root, path);
13171
- const manifestSource = await readFile23(target.file, "utf8");
13347
+ const manifestSource = await readFile21(target.file, "utf8");
13172
13348
  const manifestNext = versionKeyEdit(manifestSource, previous, next);
13173
13349
  if (!manifestNext)
13174
13350
  return failure(
@@ -13180,7 +13356,7 @@ async function bumpModuleVersion(workspace, options) {
13180
13356
  path: rel(target.file),
13181
13357
  change: `version ${previous} -> ${next}`
13182
13358
  });
13183
- const packagePath = join20(target.root, "package.json");
13359
+ const packagePath = join19(target.root, "package.json");
13184
13360
  const packageSource = await readOptional(packagePath);
13185
13361
  if (packageSource) {
13186
13362
  const edited = versionKeyEdit(packageSource, previous, next);
@@ -13192,7 +13368,7 @@ async function bumpModuleVersion(workspace, options) {
13192
13368
  });
13193
13369
  } else manual.push(`${rel(packagePath)}: version is not ${previous}`);
13194
13370
  }
13195
- const specPath = join20(target.root, spec, "module.yaml");
13371
+ const specPath = join19(target.root, spec, "module.yaml");
13196
13372
  const specSource = await readOptional(specPath);
13197
13373
  if (specSource) {
13198
13374
  const edited = specVersionEdit(specSource, previous, next);
@@ -13221,7 +13397,7 @@ async function bumpModuleVersion(workspace, options) {
13221
13397
  continue;
13222
13398
  }
13223
13399
  if (range === dependency.range) continue;
13224
- const source = await readFile23(dependent.file, "utf8");
13400
+ const source = await readFile21(dependent.file, "utf8");
13225
13401
  const edited = manifestRangeEdit(source, options.id, range);
13226
13402
  if (!edited) {
13227
13403
  manual.push(
@@ -13234,7 +13410,7 @@ async function bumpModuleVersion(workspace, options) {
13234
13410
  path: rel(dependent.file),
13235
13411
  change: `${options.id} ${dependency.range} -> ${range}`
13236
13412
  });
13237
- const dependentSpecPath = join20(dependent.root, spec, "module.yaml");
13413
+ const dependentSpecPath = join19(dependent.root, spec, "module.yaml");
13238
13414
  const dependentSpec = await readOptional(dependentSpecPath);
13239
13415
  if (!dependentSpec) continue;
13240
13416
  const specEdited = specRangeEdit(dependentSpec, options.id, range);
@@ -13379,7 +13555,7 @@ async function runExtensionCommand(workspace, extension, arguments_) {
13379
13555
  { report }
13380
13556
  );
13381
13557
  }
13382
- const spec = parseYaml7(await readFile24(specPath, "utf8"));
13558
+ const spec = parseYaml7(await readFile22(specPath, "utf8"));
13383
13559
  if (spec.status !== "approved") {
13384
13560
  return failure(
13385
13561
  "SPEC_NOT_APPROVED",
@@ -13595,7 +13771,7 @@ async function runCommand(arguments_) {
13595
13771
  if (arguments_.flags.has("all")) {
13596
13772
  const platformRoot = workspace.config.specs?.platformRoot ?? "specs";
13597
13773
  const platformSpecs = await listPlatformSpecs(
13598
- join21(workspace.root, platformRoot)
13774
+ join20(workspace.root, platformRoot)
13599
13775
  );
13600
13776
  reports.push(
13601
13777
  ...await Promise.all(
@@ -14012,7 +14188,7 @@ async function runCommand(arguments_) {
14012
14188
  ["apply", true]
14013
14189
  ])
14014
14190
  }
14015
- );
14191
+ ).catch(commandFailure);
14016
14192
  if (!granted.ok) {
14017
14193
  return failure(
14018
14194
  "MODULE_SCOPES_SYNC_FAILED",
@@ -14088,23 +14264,20 @@ async function runCommand(arguments_) {
14088
14264
  `Unknown command: ${arguments_.positionals.join(" ")}`
14089
14265
  );
14090
14266
  } catch (error) {
14091
- return failure(
14092
- error instanceof ModuleDistributionError || error instanceof RegistryError || error instanceof DatabaseMigrationError ? error.code : "COMMAND_FAILED",
14093
- error instanceof Error ? error.message : String(error)
14094
- );
14267
+ return commandFailure(error);
14095
14268
  }
14096
14269
  }
14097
14270
 
14098
14271
  // src/program.ts
14099
14272
  import { loadEnvFile } from "node:process";
14100
- import { resolve as resolve8 } from "node:path";
14273
+ import { resolve as resolve10 } from "node:path";
14101
14274
  async function runProgram(arguments_) {
14102
14275
  try {
14103
14276
  const workspace = await findWorkspace(
14104
14277
  stringFlag(arguments_, "root") ?? process.cwd()
14105
14278
  );
14106
14279
  try {
14107
- loadEnvFile(resolve8(workspace.root, ".env"));
14280
+ loadEnvFile(resolve10(workspace.root, ".env"));
14108
14281
  } catch (error) {
14109
14282
  if (error.code !== "ENOENT")
14110
14283
  return failure(
@@ -14126,20 +14299,20 @@ import { stat as stat4 } from "node:fs/promises";
14126
14299
 
14127
14300
  // src/setup-environment.ts
14128
14301
  import { randomUUID as randomUUID6 } from "node:crypto";
14129
- import { lstat as lstat8, open as open3, readFile as readFile25, rename as rename7, rm as rm11, writeFile as writeFile12 } from "node:fs/promises";
14130
- import { join as join22 } from "node:path";
14302
+ import { lstat as lstat7, open as open3, readFile as readFile23, rename as rename7, rm as rm11, writeFile as writeFile12 } from "node:fs/promises";
14303
+ import { join as join21 } from "node:path";
14131
14304
  async function readSetupEnvironment(root) {
14132
14305
  try {
14133
- return await readFile25(join22(root, ".env"), "utf8");
14306
+ return await readFile23(join21(root, ".env"), "utf8");
14134
14307
  } catch (error) {
14135
14308
  if (error.code === "ENOENT") return "";
14136
14309
  throw error;
14137
14310
  }
14138
14311
  }
14139
14312
  async function saveSetupEnvironment(root, before, updates) {
14140
- const path = join22(root, ".env");
14313
+ const path = join21(root, ".env");
14141
14314
  try {
14142
- if (!(await lstat8(path)).isFile())
14315
+ if (!(await lstat7(path)).isFile())
14143
14316
  throw new Error("Setup requires .env to be a regular file.");
14144
14317
  } catch (error) {
14145
14318
  if (error.code !== "ENOENT") throw error;
@@ -14161,8 +14334,8 @@ async function saveSetupEnvironment(root, before, updates) {
14161
14334
  return false;
14162
14335
  });
14163
14336
  const source = lines.join("\n").trimEnd() + "\n" + Object.entries(updates).map(([key, value]) => `${key}='${value}'`).join("\n") + "\n";
14164
- const temporary = join22(root, `.env.setup-${randomUUID6()}.tmp`);
14165
- const lockPath = join22(root, ".env.setup.lock");
14337
+ const temporary = join21(root, `.env.setup-${randomUUID6()}.tmp`);
14338
+ const lockPath = join21(root, ".env.setup.lock");
14166
14339
  const lock = await open3(lockPath, "wx", 384);
14167
14340
  try {
14168
14341
  await writeFile12(temporary, source, { mode: 384, flag: "wx" });