agentful 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -33,9 +33,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
33
  mod
34
34
  ));
35
35
 
36
- // node_modules/commander/lib/error.js
36
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/error.js
37
37
  var require_error = __commonJS({
38
- "node_modules/commander/lib/error.js"(exports2) {
38
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/error.js"(exports2) {
39
39
  "use strict";
40
40
  var CommanderError2 = class extends Error {
41
41
  /**
@@ -69,9 +69,9 @@ var require_error = __commonJS({
69
69
  }
70
70
  });
71
71
 
72
- // node_modules/commander/lib/argument.js
72
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/argument.js
73
73
  var require_argument = __commonJS({
74
- "node_modules/commander/lib/argument.js"(exports2) {
74
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/argument.js"(exports2) {
75
75
  "use strict";
76
76
  var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
77
77
  var Argument2 = class {
@@ -197,9 +197,9 @@ var require_argument = __commonJS({
197
197
  }
198
198
  });
199
199
 
200
- // node_modules/commander/lib/help.js
200
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/help.js
201
201
  var require_help = __commonJS({
202
- "node_modules/commander/lib/help.js"(exports2) {
202
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/help.js"(exports2) {
203
203
  "use strict";
204
204
  var { humanReadableArgName } = require_argument();
205
205
  var Help2 = class {
@@ -612,9 +612,9 @@ var require_help = __commonJS({
612
612
  }
613
613
  });
614
614
 
615
- // node_modules/commander/lib/option.js
615
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/option.js
616
616
  var require_option = __commonJS({
617
- "node_modules/commander/lib/option.js"(exports2) {
617
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/option.js"(exports2) {
618
618
  "use strict";
619
619
  var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
620
620
  var Option2 = class {
@@ -885,9 +885,9 @@ var require_option = __commonJS({
885
885
  }
886
886
  });
887
887
 
888
- // node_modules/commander/lib/suggestSimilar.js
888
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/suggestSimilar.js
889
889
  var require_suggestSimilar = __commonJS({
890
- "node_modules/commander/lib/suggestSimilar.js"(exports2) {
890
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/suggestSimilar.js"(exports2) {
891
891
  "use strict";
892
892
  var maxDistance = 3;
893
893
  function editDistance(a, b) {
@@ -966,9 +966,9 @@ var require_suggestSimilar = __commonJS({
966
966
  }
967
967
  });
968
968
 
969
- // node_modules/commander/lib/command.js
969
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/command.js
970
970
  var require_command = __commonJS({
971
- "node_modules/commander/lib/command.js"(exports2) {
971
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/lib/command.js"(exports2) {
972
972
  "use strict";
973
973
  var EventEmitter = require("events").EventEmitter;
974
974
  var childProcess = require("child_process");
@@ -3010,9 +3010,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3010
3010
  }
3011
3011
  });
3012
3012
 
3013
- // node_modules/commander/index.js
3013
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/index.js
3014
3014
  var require_commander = __commonJS({
3015
- "node_modules/commander/index.js"(exports2) {
3015
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/index.js"(exports2) {
3016
3016
  "use strict";
3017
3017
  var { Argument: Argument2 } = require_argument();
3018
3018
  var { Command: Command2 } = require_command();
@@ -3044,7 +3044,7 @@ var VERSION, brand, useColor, wrap, paint, tuiDesign, sym, ui;
3044
3044
  var init_branding = __esm({
3045
3045
  "src/branding.ts"() {
3046
3046
  "use strict";
3047
- VERSION = "0.4.6" ? "0.4.6" : null.version;
3047
+ VERSION = "0.4.7" ? "0.4.7" : null.version;
3048
3048
  brand = {
3049
3049
  name: "agentful",
3050
3050
  // the command users type
@@ -3103,9 +3103,9 @@ var init_branding = __esm({
3103
3103
  }
3104
3104
  });
3105
3105
 
3106
- // node_modules/ignore/index.js
3106
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/ignore/index.js
3107
3107
  var require_ignore = __commonJS({
3108
- "node_modules/ignore/index.js"(exports2, module2) {
3108
+ "../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/ignore/index.js"(exports2, module2) {
3109
3109
  "use strict";
3110
3110
  function makeArray(subject) {
3111
3111
  return Array.isArray(subject) ? subject : [subject];
@@ -3824,7 +3824,7 @@ var init_plugin = __esm({
3824
3824
  }
3825
3825
  });
3826
3826
 
3827
- // node_modules/commander/esm.mjs
3827
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/commander/esm.mjs
3828
3828
  var import_index = __toESM(require_commander(), 1);
3829
3829
  var {
3830
3830
  program,
@@ -4785,7 +4785,7 @@ init_branding();
4785
4785
  var import_node_fs4 = require("fs");
4786
4786
  var import_node_path6 = require("path");
4787
4787
 
4788
- // node_modules/fflate/esm/index.mjs
4788
+ // ../../../../../../../../Users/gn/Labor/mainmvp/cli/node_modules/fflate/esm/index.mjs
4789
4789
  var import_module = require("module");
4790
4790
  var require2 = (0, import_module.createRequire)("/");
4791
4791
  var _a;
@@ -5597,18 +5597,28 @@ function detectDistDir(rootDir, override) {
5597
5597
  }
5598
5598
 
5599
5599
  // src/lib/preflight.ts
5600
- var import_node_fs5 = require("fs");
5601
- var import_node_path7 = require("path");
5600
+ var import_node_fs6 = require("fs");
5601
+ var import_node_path8 = require("path");
5602
5602
 
5603
5603
  // ../platform-contract/contract.json
5604
5604
  var contract_default = {
5605
5605
  $comment: "Single source of truth for the platform publish contract (PRD AP6a, planned/cli-push-to-workspace-transition-findings-and-prd-2026-08-17.md). Consumers: cli/src/lib/preflight.ts renders directly from this file; build engine (infrastructure/lambda/build-engine/handler.ts) and executor (opencode-lambda/executor/runtime/opencode_runner.py) are parity-checked against it by ./check-parity.py until AP4/AP5 move them onto it; AP0 instructions/skills render from it later. Bump schema_version on breaking shape changes. See README.md.",
5606
5606
  schema_version: 1,
5607
- contract_statement: "This platform publishes static files. Your app has no server process of its own \u2014 server-side logic runs as Managed Server Actions (short request/response functions) or on an API of your own that you connect. You cannot set build-time env vars or secrets: the workspace build injects only a fixed allowlist of public client values, and the `agentful push` build injects none.",
5607
+ contract_statement: "This platform publishes static files. Your app has no server process of its own \u2014 server-side logic runs as Managed Server Actions (short request/response functions) or on an API of your own that you connect. You cannot set build-time env vars or secrets: every cloud build injects the same fixed allowlist of public client values, and nothing else.",
5608
5608
  publish: {
5609
5609
  server_process: false,
5610
5610
  build_env_vars: false,
5611
- $comment_build_env: "false = nobody can SET a build variable or build secret. Two build paths exist and they differ: the workspace executor injects a fixed allowlist of PUBLIC client values (VITE_PROJECT_ID/PUBLIC_PROJECT_ID, and for a BYO Supabase database its URL + publishable key as VITE_/PUBLIC_/NEXT_PUBLIC_); the build engine behind `agentful push` injects nothing beyond NODE_ENV. Code that must build on both paths keeps public values in an ordinary source constant.",
5611
+ $comment_build_env: "false = nobody can SET a build variable or build secret. Two build paths exist \u2014 the workspace executor (end of an agent turn) and the build engine (the workspace's Build button and `agentful push`) \u2014 and both inject the SAME fixed allowlist of PUBLIC client values, listed under build_env. The values come from one function on both paths (aws-services/workspace-manager/client_config.py); check-parity.py (check 13) pins the names. Until 2026-09 the build engine injected nothing, so an app that read import.meta.env.VITE_SUPABASE_URL worked after the agent's turn and lost its database on the next Build click \u2014 without a build error. A public value outside the allowlist still belongs in an ordinary source constant.",
5612
+ build_env: {
5613
+ $comment: "What a cloud build defines, and nothing else. `injected` = suffix x prefixes; `when: byo_supabase` means only while the project's Backend tab has an own Supabase database connected (URL + publishable key; a secret key stored in that slot is refused, never shipped). A read of <public prefix><injected suffix> that the build does NOT define fails the build (422 undefined_build_env): undefined there is a broken app, not a default. Any other read of a public-prefixed name that nothing defines is a warning, because `import.meta.env.VITE_API_BASE ?? '/api'` is a legitimate pattern. `bundler_builtins` are set by the framework itself and are never reported.",
5614
+ public_prefixes: ["VITE_", "PUBLIC_", "NEXT_PUBLIC_"],
5615
+ injected: [
5616
+ { suffix: "PROJECT_ID", prefixes: ["VITE_", "PUBLIC_"], when: "always" },
5617
+ { suffix: "SUPABASE_URL", prefixes: ["VITE_", "PUBLIC_", "NEXT_PUBLIC_"], when: "byo_supabase" },
5618
+ { suffix: "SUPABASE_ANON_KEY", prefixes: ["VITE_", "PUBLIC_", "NEXT_PUBLIC_"], when: "byo_supabase" }
5619
+ ],
5620
+ bundler_builtins: ["PUBLIC_URL"]
5621
+ },
5612
5622
  published_prefix: "dist/",
5613
5623
  canonical_output_check: "root_index_html",
5614
5624
  $comment_output: "Canonical end-to-end contract (AP4): a root-level index.html inside the framework's output dir. Deliberately stricter than the executor's historical index.htm/200.html acceptance \u2014 both builders converge on THIS, not on each other (deployment gate and publish self-heal require dist/index.html)."
@@ -5806,7 +5816,7 @@ var contract_default = {
5806
5816
  build_attempt_schema: {
5807
5817
  file: "deployments/latest-build.json",
5808
5818
  status_values: ["running", "success", "failed"],
5809
- phase_codes: ["unsupported_project_type", "install", "build", "missing_output", "upload"],
5819
+ phase_codes: ["unsupported_project_type", "client_env", "install", "build", "missing_output", "upload"],
5810
5820
  fields: {
5811
5821
  schema_version: "int \u2014 copy of this contract's schema_version",
5812
5822
  build_id: "string \u2014 unique per attempt",
@@ -5826,6 +5836,154 @@ var contract_default = {
5826
5836
  }
5827
5837
  };
5828
5838
 
5839
+ // ../platform-contract/buildEnv.ts
5840
+ var import_node_fs5 = require("fs");
5841
+ var import_node_path7 = require("path");
5842
+ var BUILD_ENV = contract_default.publish.build_env;
5843
+ var PUBLIC_PREFIXES = BUILD_ENV.public_prefixes;
5844
+ var BUILTINS = new Set(BUILD_ENV.bundler_builtins);
5845
+ var INJECTABLE_NAMES = new Set(
5846
+ BUILD_ENV.injected.flatMap((e) => e.prefixes.map((p) => `${p}${e.suffix}`))
5847
+ );
5848
+ var ALWAYS_DEFINED_NAMES = new Set(
5849
+ BUILD_ENV.injected.filter((e) => e.when === "always").flatMap((e) => e.prefixes.map((p) => `${p}${e.suffix}`))
5850
+ );
5851
+ var splitName = (name) => {
5852
+ const prefix = PUBLIC_PREFIXES.find((p) => name.startsWith(p));
5853
+ return prefix ? { prefix, suffix: name.slice(prefix.length) } : null;
5854
+ };
5855
+ var injectedEntry = (suffix) => BUILD_ENV.injected.find((e) => e.suffix === suffix);
5856
+ var SCAN_FILE = /\.(js|jsx|ts|tsx|mjs|cjs|vue|svelte|astro)$/;
5857
+ var SKIP_FILE = /\.d\.ts$|\.(test|spec)\.[a-z]+$/;
5858
+ var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", "out", ".nuxt", ".output", "coverage"]);
5859
+ var SCAN_FILE_BUDGET = 5e3;
5860
+ var MAX_SCAN_BYTES = 1024 * 1024;
5861
+ var ENV_OBJECT = String.raw`(?:import\.meta\.env|process\.env)`;
5862
+ var MEMBER_READ = new RegExp(
5863
+ String.raw`\b${ENV_OBJECT}\s*(?:\??\.\s*([A-Z][A-Z0-9_]*)|\[\s*['"]([A-Z][A-Z0-9_]*)['"]\s*\])(\s*(?:\?\?|\|\|))?`,
5864
+ "g"
5865
+ );
5866
+ var DESTRUCTURED_READ = new RegExp(String.raw`\{([^{}]*)\}\s*=\s*${ENV_OBJECT}\b`, "g");
5867
+ var QUOTED = /'(?:[^'\\\n]|\\.)*'|"(?:[^"\\\n]|\\.)*"/g;
5868
+ var MENTIONS_ENV = /\benv\s*[.[]/;
5869
+ var stripNonCode = (text) => text.replace(QUOTED, (quoted) => MENTIONS_ENV.test(quoted) ? "''" : quoted).replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:'"`\\])\/\/[^\n]*/g, "$1");
5870
+ var isReportable = (name) => !BUILTINS.has(name) && splitName(name) !== null;
5871
+ function collectFiles2(dir, out, budget) {
5872
+ if (budget.left <= 0 || !(0, import_node_fs5.existsSync)(dir)) return;
5873
+ for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true })) {
5874
+ if (budget.left <= 0) return;
5875
+ const abs = (0, import_node_path7.join)(dir, entry.name);
5876
+ if (entry.isDirectory()) {
5877
+ if (!SKIP_DIRS.has(entry.name)) collectFiles2(abs, out, budget);
5878
+ } else if (entry.isFile() && SCAN_FILE.test(entry.name) && !SKIP_FILE.test(entry.name)) {
5879
+ budget.left--;
5880
+ out.push(abs);
5881
+ }
5882
+ }
5883
+ }
5884
+ function scanEnvReads(rootDir) {
5885
+ const files = [];
5886
+ collectFiles2(rootDir, files, { left: SCAN_FILE_BUDGET });
5887
+ const reads = [];
5888
+ for (const abs of files) {
5889
+ let text;
5890
+ try {
5891
+ text = (0, import_node_fs5.readFileSync)(abs, "utf8");
5892
+ } catch {
5893
+ continue;
5894
+ }
5895
+ if (text.length > MAX_SCAN_BYTES || !/\benv\b/.test(text)) continue;
5896
+ text = stripNonCode(text);
5897
+ const inFile = /* @__PURE__ */ new Map();
5898
+ const note = (name, hasFallback) => {
5899
+ if (isReportable(name)) inFile.set(name, (inFile.get(name) ?? true) && hasFallback);
5900
+ };
5901
+ for (const m of text.matchAll(MEMBER_READ)) note(m[1] || m[2], Boolean(m[3]));
5902
+ for (const m of text.matchAll(DESTRUCTURED_READ)) {
5903
+ for (const part of m[1].split(",")) {
5904
+ const field = /^\s*([A-Z][A-Z0-9_]*)\s*(?::\s*[A-Za-z_$][\w$]*\s*)?(=)?/.exec(part);
5905
+ if (field) note(field[1], Boolean(field[2]));
5906
+ }
5907
+ }
5908
+ const file = (0, import_node_path7.relative)(rootDir, abs).split(import_node_path7.sep).join("/");
5909
+ for (const [name, hasFallback] of inFile) reads.push({ name, file, hasFallback });
5910
+ }
5911
+ return reads;
5912
+ }
5913
+ function envFileNames(rootDir) {
5914
+ const names = /* @__PURE__ */ new Set();
5915
+ if (!(0, import_node_fs5.existsSync)(rootDir)) return names;
5916
+ for (const entry of (0, import_node_fs5.readdirSync)(rootDir, { withFileTypes: true })) {
5917
+ if (!entry.isFile() || !(entry.name === ".env" || entry.name.startsWith(".env."))) continue;
5918
+ let text;
5919
+ try {
5920
+ text = (0, import_node_fs5.readFileSync)((0, import_node_path7.join)(rootDir, entry.name), "utf8");
5921
+ } catch {
5922
+ continue;
5923
+ }
5924
+ for (const line of text.split("\n")) {
5925
+ const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line);
5926
+ if (m) names.add(m[1]);
5927
+ }
5928
+ }
5929
+ return names;
5930
+ }
5931
+ var sampleFiles = (files) => files.slice(0, 3).join(", ") + (files.length > 3 ? ", \u2026" : "");
5932
+ var prefixList = (prefixes) => prefixes.map((p) => `${p}*`).join("/");
5933
+ function platformHint(name, opts) {
5934
+ const { prefix, suffix } = splitName(name);
5935
+ const entry = injectedEntry(suffix);
5936
+ if (!entry.prefixes.includes(prefix)) {
5937
+ return `The platform defines ${suffix} only as ${entry.prefixes.map((p) => `${p}${suffix}`).join(" and ")} \u2014 read one of those, or keep the value in an ordinary source constant.`;
5938
+ }
5939
+ if (entry.when === "byo_supabase") {
5940
+ if ((opts.rejected || []).includes(suffix)) {
5941
+ return "The key stored for this database looks like a Supabase SECRET key. The platform refuses to put it into a public bundle \u2014 store the publishable (anon) key as `database.anon_key` in the Backend tab instead.";
5942
+ }
5943
+ if (opts.provider === "supabase" && (opts.missing || []).includes(suffix)) {
5944
+ return suffix === "SUPABASE_URL" ? "Your own Supabase database is connected, but no https project URL is stored \u2014 set it in the Backend tab (Database)." : "Your own Supabase database is connected, but no publishable key is stored \u2014 add it in the Backend tab as `database.anon_key`.";
5945
+ }
5946
+ return `The platform defines ${suffix} (as ${prefixList(entry.prefixes)}) only while your own Supabase database is connected in the Backend tab (Database \u2192 own Supabase). Connect it there, or keep the public value in an ordinary source constant.`;
5947
+ }
5948
+ return "Keep the public value in an ordinary source constant.";
5949
+ }
5950
+ function judgeEnvReads(reads, opts) {
5951
+ const byName = /* @__PURE__ */ new Map();
5952
+ for (const read of reads) {
5953
+ if (opts.defined.has(read.name)) continue;
5954
+ byName.set(read.name, [...byName.get(read.name) || [], read]);
5955
+ }
5956
+ const verdict = { errors: [], warnings: [] };
5957
+ const build = opts.backendUnknown ? "the cloud build" : "this build";
5958
+ for (const name of [...byName.keys()].sort()) {
5959
+ const group = byName.get(name);
5960
+ const files = sampleFiles(group.map((r) => r.file).sort());
5961
+ const { prefix, suffix } = splitName(name);
5962
+ const entry = injectedEntry(suffix);
5963
+ const taught = entry !== void 0;
5964
+ const bare = group.filter((r) => !r.hasFallback);
5965
+ const local = opts.localOnly?.has(name) ? " Your local .env defines it, but .env files never leave this machine." : "";
5966
+ if (opts.backendUnknown && entry && entry.when === "byo_supabase" && entry.prefixes.includes(prefix)) {
5967
+ verdict.warnings.push(
5968
+ `${name} is read in ${files}. The cloud build defines it only while your own Supabase database is connected in the Backend tab (Database \u2192 own Supabase)` + (bare.length > 0 ? " \u2014 without that it rejects the build, because the value would compile to `undefined` without any build error." : "; without that the app runs on its own fallback.") + local
5969
+ );
5970
+ } else if (taught && bare.length > 0) {
5971
+ verdict.errors.push(
5972
+ `${name} is read in ${sampleFiles(bare.map((r) => r.file).sort())}, but ${build} does not define it \u2014 it would compile to \`undefined\` without any build error. ${platformHint(name, opts)}${local}`
5973
+ );
5974
+ } else if (taught) {
5975
+ verdict.warnings.push(
5976
+ `${name} is read in ${files} and ${build} does not define it \u2014 the app runs on its own fallback. ${platformHint(name, opts)}${local}`
5977
+ );
5978
+ } else {
5979
+ verdict.warnings.push(
5980
+ `${name} is read in ${files}, but no cloud build defines it \u2014 it compiles to \`undefined\`. This platform sets no build variables of your own: keep public values in an ordinary source constant (a fallback such as \`?? '/api'\` is fine).${local}`
5981
+ );
5982
+ }
5983
+ }
5984
+ return verdict;
5985
+ }
5986
+
5829
5987
  // src/lib/preflight.ts
5830
5988
  function feature(id) {
5831
5989
  const found = contract_default.forbidden_server_features.find((f) => f.id === id);
@@ -5853,14 +6011,14 @@ var STATIC_EXPORT = /output\s*:\s*['"]export['"]/;
5853
6011
  var SOURCE_FILE = /\.(js|jsx|ts|tsx|mjs)$/;
5854
6012
  var GET_SERVER_SIDE_PROPS = /export\s+(?:async\s+)?(?:function|const|let|var)\s+getServerSideProps\b|export\s*\{[^}]*\bgetServerSideProps\b[^}]*\}/;
5855
6013
  var USE_SERVER = /^\s*(['"])use server\1\s*;?\s*$/m;
5856
- var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", "out"]);
5857
- var SCAN_FILE_BUDGET = 5e3;
6014
+ var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", "out"]);
6015
+ var SCAN_FILE_BUDGET2 = 5e3;
5858
6016
  function detectFramework(rootDir) {
5859
- const pkgPath = (0, import_node_path7.join)(rootDir, "package.json");
5860
- if (!(0, import_node_fs5.existsSync)(pkgPath)) return "vanilla";
6017
+ const pkgPath = (0, import_node_path8.join)(rootDir, "package.json");
6018
+ if (!(0, import_node_fs6.existsSync)(pkgPath)) return "vanilla";
5861
6019
  let pkg;
5862
6020
  try {
5863
- pkg = JSON.parse((0, import_node_fs5.readFileSync)(pkgPath, "utf8"));
6021
+ pkg = JSON.parse((0, import_node_fs6.readFileSync)(pkgPath, "utf8"));
5864
6022
  } catch {
5865
6023
  return "unknown";
5866
6024
  }
@@ -5870,32 +6028,32 @@ function detectFramework(rootDir) {
5870
6028
  }
5871
6029
  function readDeps(rootDir) {
5872
6030
  try {
5873
- const pkg = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path7.join)(rootDir, "package.json"), "utf8"));
6031
+ const pkg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path8.join)(rootDir, "package.json"), "utf8"));
5874
6032
  return { ...pkg.dependencies, ...pkg.devDependencies };
5875
6033
  } catch {
5876
6034
  return {};
5877
6035
  }
5878
6036
  }
5879
6037
  function findFiles(rootDir, dir, pattern, out, cap = 20) {
5880
- if (out.length >= cap || !(0, import_node_fs5.existsSync)(dir)) return;
5881
- for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true })) {
6038
+ if (out.length >= cap || !(0, import_node_fs6.existsSync)(dir)) return;
6039
+ for (const entry of (0, import_node_fs6.readdirSync)(dir, { withFileTypes: true })) {
5882
6040
  if (out.length >= cap) return;
5883
- const abs = (0, import_node_path7.join)(dir, entry.name);
6041
+ const abs = (0, import_node_path8.join)(dir, entry.name);
5884
6042
  if (entry.isDirectory()) {
5885
- if (!SKIP_DIRS.has(entry.name)) findFiles(rootDir, abs, pattern, out, cap);
6043
+ if (!SKIP_DIRS2.has(entry.name)) findFiles(rootDir, abs, pattern, out, cap);
5886
6044
  } else if (entry.isFile() && pattern.test(entry.name)) {
5887
- out.push((0, import_node_path7.relative)(rootDir, abs).split(import_node_path7.sep).join("/"));
6045
+ out.push((0, import_node_path8.relative)(rootDir, abs).split(import_node_path8.sep).join("/"));
5888
6046
  }
5889
6047
  }
5890
6048
  }
5891
6049
  var sample = (list) => list.slice(0, 3).join(", ") + (list.length > 3 ? ", \u2026" : "");
5892
6050
  function collectSourceFiles(dir, out, budget) {
5893
- if (budget.left <= 0 || !(0, import_node_fs5.existsSync)(dir)) return;
5894
- for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true })) {
6051
+ if (budget.left <= 0 || !(0, import_node_fs6.existsSync)(dir)) return;
6052
+ for (const entry of (0, import_node_fs6.readdirSync)(dir, { withFileTypes: true })) {
5895
6053
  if (budget.left <= 0) return;
5896
- const abs = (0, import_node_path7.join)(dir, entry.name);
6054
+ const abs = (0, import_node_path8.join)(dir, entry.name);
5897
6055
  if (entry.isDirectory()) {
5898
- if (!SKIP_DIRS.has(entry.name)) collectSourceFiles(abs, out, budget);
6056
+ if (!SKIP_DIRS2.has(entry.name)) collectSourceFiles(abs, out, budget);
5899
6057
  } else if (entry.isFile() && SOURCE_FILE.test(entry.name)) {
5900
6058
  budget.left--;
5901
6059
  out.push(abs);
@@ -5905,10 +6063,10 @@ function collectSourceFiles(dir, out, budget) {
5905
6063
  function checkNextjs(rootDir) {
5906
6064
  const issues = [];
5907
6065
  const warnings = [];
5908
- const configName = NEXT_CONFIG_BASENAMES.find((name) => (0, import_node_fs5.existsSync)((0, import_node_path7.join)(rootDir, name)));
6066
+ const configName = NEXT_CONFIG_BASENAMES.find((name) => (0, import_node_fs6.existsSync)((0, import_node_path8.join)(rootDir, name)));
5909
6067
  let hasStaticExport = true;
5910
6068
  if (configName) {
5911
- const config = (0, import_node_fs5.readFileSync)((0, import_node_path7.join)(rootDir, configName), "utf8");
6069
+ const config = (0, import_node_fs6.readFileSync)((0, import_node_path8.join)(rootDir, configName), "utf8");
5912
6070
  hasStaticExport = STATIC_EXPORT.test(config);
5913
6071
  if (!hasStaticExport) {
5914
6072
  issues.push(
@@ -5922,31 +6080,31 @@ function checkNextjs(rootDir) {
5922
6080
  const hard = [];
5923
6081
  const pagesApi = [];
5924
6082
  for (const apiDir of PAGES_API_DIRS) {
5925
- findFiles(rootDir, (0, import_node_path7.join)(rootDir, apiDir), /\.(js|ts|jsx|tsx|mjs)$/, pagesApi);
6083
+ findFiles(rootDir, (0, import_node_path8.join)(rootDir, apiDir), /\.(js|ts|jsx|tsx|mjs)$/, pagesApi);
5926
6084
  }
5927
6085
  if (pagesApi.length > 0) hard.push(`pages/api/* routes (${pagesApi.length} file(s))`);
5928
6086
  const middlewareFiles = [];
5929
6087
  for (const base of ["", "src"]) {
5930
- const dir = base ? (0, import_node_path7.join)(rootDir, base) : rootDir;
5931
- if (!(0, import_node_fs5.existsSync)(dir)) continue;
5932
- for (const entry of (0, import_node_fs5.readdirSync)(dir)) {
5933
- if (MIDDLEWARE_FILE.test(entry)) middlewareFiles.push((0, import_node_path7.join)(base, entry).split(import_node_path7.sep).join("/"));
6088
+ const dir = base ? (0, import_node_path8.join)(rootDir, base) : rootDir;
6089
+ if (!(0, import_node_fs6.existsSync)(dir)) continue;
6090
+ for (const entry of (0, import_node_fs6.readdirSync)(dir)) {
6091
+ if (MIDDLEWARE_FILE.test(entry)) middlewareFiles.push((0, import_node_path8.join)(base, entry).split(import_node_path8.sep).join("/"));
5934
6092
  }
5935
6093
  }
5936
6094
  hard.push(...middlewareFiles);
5937
6095
  const sourceFiles = [];
5938
- collectSourceFiles(rootDir, sourceFiles, { left: SCAN_FILE_BUDGET });
6096
+ collectSourceFiles(rootDir, sourceFiles, { left: SCAN_FILE_BUDGET2 });
5939
6097
  const gssp = [];
5940
6098
  const useServer = [];
5941
6099
  for (const abs of sourceFiles) {
5942
6100
  if (gssp.length >= 20 && useServer.length >= 20) break;
5943
6101
  let text;
5944
6102
  try {
5945
- text = (0, import_node_fs5.readFileSync)(abs, "utf8");
6103
+ text = (0, import_node_fs6.readFileSync)(abs, "utf8");
5946
6104
  } catch {
5947
6105
  continue;
5948
6106
  }
5949
- const rel = (0, import_node_path7.relative)(rootDir, abs).split(import_node_path7.sep).join("/");
6107
+ const rel = (0, import_node_path8.relative)(rootDir, abs).split(import_node_path8.sep).join("/");
5950
6108
  if (gssp.length < 20 && GET_SERVER_SIDE_PROPS.test(text)) gssp.push(rel);
5951
6109
  if (useServer.length < 20 && USE_SERVER.test(text)) useServer.push(rel);
5952
6110
  }
@@ -5954,7 +6112,7 @@ function checkNextjs(rootDir) {
5954
6112
  if (useServer.length > 0) hard.push(`'use server' actions (${sample(useServer)})`);
5955
6113
  const routeFiles = [];
5956
6114
  for (const appDir of APP_DIRS) {
5957
- findFiles(rootDir, (0, import_node_path7.join)(rootDir, appDir), ROUTE_HANDLER_FILE, routeFiles);
6115
+ findFiles(rootDir, (0, import_node_path8.join)(rootDir, appDir), ROUTE_HANDLER_FILE, routeFiles);
5958
6116
  }
5959
6117
  if (routeFiles.length > 0) {
5960
6118
  const label = `${routeFiles.length} route handler(s) (${sample(routeFiles)})`;
@@ -5988,6 +6146,17 @@ function checkNextjs(rootDir) {
5988
6146
  }
5989
6147
  return { issues, warnings };
5990
6148
  }
6149
+ function checkBuildEnv(rootDir) {
6150
+ const verdict = judgeEnvReads(scanEnvReads(rootDir), {
6151
+ defined: ALWAYS_DEFINED_NAMES,
6152
+ backendUnknown: true,
6153
+ localOnly: envFileNames(rootDir)
6154
+ });
6155
+ return [
6156
+ ...verdict.errors.map((e) => `The cloud build will reject this project: ${e}`),
6157
+ ...verdict.warnings
6158
+ ];
6159
+ }
5991
6160
  function runPreflight(rootDir) {
5992
6161
  const framework = detectFramework(rootDir);
5993
6162
  const issues = [];
@@ -6002,17 +6171,18 @@ function runPreflight(rootDir) {
6002
6171
  issues.push(...next.issues);
6003
6172
  warnings.push(...next.warnings);
6004
6173
  }
6174
+ if (framework !== "vanilla") warnings.push(...checkBuildEnv(rootDir));
6005
6175
  return { framework, issues, warnings };
6006
6176
  }
6007
6177
 
6008
6178
  // src/lib/backendDecl.ts
6009
- var import_node_fs6 = require("fs");
6010
- var import_node_path8 = require("path");
6179
+ var import_node_fs7 = require("fs");
6180
+ var import_node_path9 = require("path");
6011
6181
  function readBackendDeclaration(dir = process.cwd()) {
6012
- const path = (0, import_node_path8.join)(dir, ".agentful", "backend.json");
6013
- if (!(0, import_node_fs6.existsSync)(path)) return null;
6182
+ const path = (0, import_node_path9.join)(dir, ".agentful", "backend.json");
6183
+ if (!(0, import_node_fs7.existsSync)(path)) return null;
6014
6184
  try {
6015
- const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf8"));
6185
+ const parsed = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
6016
6186
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
6017
6187
  const collections = Array.isArray(parsed.collections) ? parsed.collections.filter((c) => c && typeof c === "object" && !Array.isArray(c)) : [];
6018
6188
  const secrets = Array.isArray(parsed.secrets) ? parsed.secrets.filter((s) => s && typeof s === "object" && !Array.isArray(s)) : [];
@@ -6056,19 +6226,19 @@ function describeBackendDeclaration(decl) {
6056
6226
  function backendTabUrl(userId, projectId) {
6057
6227
  return `${APP_URL}/workspace/${userId}/${projectId}?view=backend`;
6058
6228
  }
6059
- var ACTIONS_DIR = (0, import_node_path8.join)(".server", "actions");
6229
+ var ACTIONS_DIR = (0, import_node_path9.join)(".server", "actions");
6060
6230
  var ACTION_NAME = /^[a-z][a-z0-9_-]{0,62}$/;
6061
6231
  function checkBackendDeclaration(rootDir = process.cwd()) {
6062
6232
  const issues = [];
6063
6233
  const warnings = [];
6064
- const actionsDir = (0, import_node_path8.join)(rootDir, ACTIONS_DIR);
6234
+ const actionsDir = (0, import_node_path9.join)(rootDir, ACTIONS_DIR);
6065
6235
  const presentFiles = /* @__PURE__ */ new Set();
6066
- if ((0, import_node_fs6.existsSync)(actionsDir)) {
6067
- for (const entry of (0, import_node_fs6.readdirSync)(actionsDir)) {
6068
- const abs = (0, import_node_path8.join)(actionsDir, entry);
6236
+ if ((0, import_node_fs7.existsSync)(actionsDir)) {
6237
+ for (const entry of (0, import_node_fs7.readdirSync)(actionsDir)) {
6238
+ const abs = (0, import_node_path9.join)(actionsDir, entry);
6069
6239
  let isDir = false;
6070
6240
  try {
6071
- isDir = (0, import_node_fs6.statSync)(abs).isDirectory();
6241
+ isDir = (0, import_node_fs7.statSync)(abs).isDirectory();
6072
6242
  } catch {
6073
6243
  continue;
6074
6244
  }
@@ -6285,8 +6455,8 @@ function describeBackendState(state) {
6285
6455
  }
6286
6456
 
6287
6457
  // src/lib/backendConsent.ts
6288
- var import_node_fs7 = require("fs");
6289
- var import_node_path9 = require("path");
6458
+ var import_node_fs8 = require("fs");
6459
+ var import_node_path10 = require("path");
6290
6460
  var import_promises2 = require("readline/promises");
6291
6461
  function declaresManagedDatabase(decl) {
6292
6462
  if (!decl) return false;
@@ -6312,10 +6482,10 @@ function consentQuestion(decl) {
6312
6482
  'It is the same switch as the Backend tab; this push then applies the declaration. A "no" is remembered for this project (`agentful push --yes` or `agentful backend` enables it later).'
6313
6483
  ].join("\n");
6314
6484
  }
6315
- var consentFile = () => (0, import_node_path9.join)(configDir(), "backend-consent.json");
6485
+ var consentFile = () => (0, import_node_path10.join)(configDir(), "backend-consent.json");
6316
6486
  function readConsentFile() {
6317
6487
  try {
6318
- const raw = JSON.parse((0, import_node_fs7.readFileSync)(consentFile(), "utf8"));
6488
+ const raw = JSON.parse((0, import_node_fs8.readFileSync)(consentFile(), "utf8"));
6319
6489
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
6320
6490
  } catch {
6321
6491
  return {};
@@ -6327,15 +6497,15 @@ function hasRememberedDecline(projectId) {
6327
6497
  function rememberDecline(projectId) {
6328
6498
  const all = readConsentFile();
6329
6499
  all[projectId] = { declined_at: (/* @__PURE__ */ new Date()).toISOString() };
6330
- (0, import_node_fs7.mkdirSync)(configDir(), { recursive: true });
6331
- (0, import_node_fs7.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
6500
+ (0, import_node_fs8.mkdirSync)(configDir(), { recursive: true });
6501
+ (0, import_node_fs8.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
6332
6502
  }
6333
6503
  function forgetDecline(projectId) {
6334
- if (!(0, import_node_fs7.existsSync)(consentFile())) return;
6504
+ if (!(0, import_node_fs8.existsSync)(consentFile())) return;
6335
6505
  const all = readConsentFile();
6336
6506
  if (!(projectId in all)) return;
6337
6507
  delete all[projectId];
6338
- (0, import_node_fs7.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
6508
+ (0, import_node_fs8.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
6339
6509
  }
6340
6510
  async function enableManagedDatabase(auth, userId, projectId) {
6341
6511
  try {
@@ -6543,13 +6713,14 @@ async function pushCommand(opts) {
6543
6713
  ui.step("Building in the cloud (this can take a few minutes)\u2026");
6544
6714
  const buildStartedAt = Date.now();
6545
6715
  try {
6546
- await request(`${PB_URL}/api/workspaces/${userId}/${projectId}/build`, {
6716
+ const built = await request(`${PB_URL}/api/workspaces/${userId}/${projectId}/build`, {
6547
6717
  method: "POST",
6548
6718
  token: auth.pb_token,
6549
6719
  body: {},
6550
6720
  timeoutMs: 66e4
6551
6721
  });
6552
6722
  ui.info("Build finished");
6723
+ for (const warning of built?.warnings ?? []) ui.warn(warning);
6553
6724
  } catch (err2) {
6554
6725
  if (err2 instanceof ApiError && err2.code === "network_error") {
6555
6726
  ui.warn("Connection dropped during the build \u2014 polling for the result\u2026");
@@ -6712,15 +6883,15 @@ async function openCommand() {
6712
6883
  // src/commands/tui.ts
6713
6884
  var import_node_child_process6 = require("child_process");
6714
6885
  var import_promises4 = require("readline/promises");
6715
- var import_node_path20 = require("path");
6886
+ var import_node_path21 = require("path");
6716
6887
 
6717
6888
  // src/lib/binWrapper.ts
6718
- var import_node_fs8 = require("fs");
6719
- var import_node_path10 = require("path");
6889
+ var import_node_fs9 = require("fs");
6890
+ var import_node_path11 = require("path");
6720
6891
  var import_node_os3 = require("os");
6721
6892
  function ensureCliOnPath() {
6722
- const binDir = (0, import_node_path10.join)((0, import_node_os3.homedir)(), ".local", "share", "agentful", "bin");
6723
- (0, import_node_fs8.mkdirSync)(binDir, { recursive: true });
6893
+ const binDir = (0, import_node_path11.join)((0, import_node_os3.homedir)(), ".local", "share", "agentful", "bin");
6894
+ (0, import_node_fs9.mkdirSync)(binDir, { recursive: true });
6724
6895
  const entry = process.argv[1];
6725
6896
  if (!entry) return binDir;
6726
6897
  const restore = (name) => {
@@ -6729,8 +6900,8 @@ function ensureCliOnPath() {
6729
6900
  ` : `export ${name}=${JSON.stringify(original)}
6730
6901
  `;
6731
6902
  };
6732
- const wrapper = (0, import_node_path10.join)(binDir, "agentful");
6733
- (0, import_node_fs8.writeFileSync)(
6903
+ const wrapper = (0, import_node_path11.join)(binDir, "agentful");
6904
+ (0, import_node_fs9.writeFileSync)(
6734
6905
  wrapper,
6735
6906
  `#!/bin/sh
6736
6907
  # Generated by the Agentful CLI so the coding agent can run \`agentful \u2026\`.
@@ -6740,7 +6911,7 @@ function ensureCliOnPath() {
6740
6911
  "utf8"
6741
6912
  );
6742
6913
  try {
6743
- (0, import_node_fs8.chmodSync)(wrapper, 493);
6914
+ (0, import_node_fs9.chmodSync)(wrapper, 493);
6744
6915
  } catch {
6745
6916
  }
6746
6917
  return binDir;
@@ -6750,9 +6921,9 @@ function ensureCliOnPath() {
6750
6921
  init_branding();
6751
6922
 
6752
6923
  // src/lib/engine.ts
6753
- var import_node_fs9 = require("fs");
6924
+ var import_node_fs10 = require("fs");
6754
6925
  var import_node_crypto = require("crypto");
6755
- var import_node_path11 = require("path");
6926
+ var import_node_path12 = require("path");
6756
6927
  var import_node_os4 = require("os");
6757
6928
  var import_node_child_process3 = require("child_process");
6758
6929
  var import_node_stream = require("stream");
@@ -6797,8 +6968,8 @@ function platformKey() {
6797
6968
  );
6798
6969
  }
6799
6970
  function cacheDir(version) {
6800
- const base = process.env.XDG_CACHE_HOME || (0, import_node_path11.join)((0, import_node_os4.homedir)(), ".cache");
6801
- return (0, import_node_path11.join)(base, "agentful", "engine", version);
6971
+ const base = process.env.XDG_CACHE_HOME || (0, import_node_path12.join)((0, import_node_os4.homedir)(), ".cache");
6972
+ return (0, import_node_path12.join)(base, "agentful", "engine", version);
6802
6973
  }
6803
6974
  async function fetchManifest() {
6804
6975
  try {
@@ -6809,7 +6980,7 @@ async function fetchManifest() {
6809
6980
  }
6810
6981
  async function sha256File(path) {
6811
6982
  const hash = (0, import_node_crypto.createHash)("sha256");
6812
- await (0, import_promises3.pipeline)((0, import_node_fs9.createReadStream)(path), hash);
6983
+ await (0, import_promises3.pipeline)((0, import_node_fs10.createReadStream)(path), hash);
6813
6984
  return hash.digest("hex");
6814
6985
  }
6815
6986
  async function ensureEngine() {
@@ -6818,12 +6989,12 @@ async function ensureEngine() {
6818
6989
  noticeIfOutdated(manifest);
6819
6990
  const version = manifest?.engine_version || FALLBACK_ENGINE_VERSION;
6820
6991
  const dir = cacheDir(version);
6821
- const binPath = (0, import_node_path11.join)(dir, ENGINE_BINARY);
6822
- if ((0, import_node_fs9.existsSync)(binPath)) return binPath;
6992
+ const binPath = (0, import_node_path12.join)(dir, ENGINE_BINARY);
6993
+ if ((0, import_node_fs10.existsSync)(binPath)) return binPath;
6823
6994
  const artifact = manifest?.artifacts?.[key];
6824
6995
  const url = artifact?.url || `${APP_URL}/cli/engine/${version}/${key}${key.startsWith("darwin") ? ".zip" : ".tar.gz"}`;
6825
- (0, import_node_fs9.mkdirSync)(dir, { recursive: true });
6826
- const archivePath = (0, import_node_path11.join)(dir, key.startsWith("darwin") ? "engine.zip" : "engine.tar.gz");
6996
+ (0, import_node_fs10.mkdirSync)(dir, { recursive: true });
6997
+ const archivePath = (0, import_node_path12.join)(dir, key.startsWith("darwin") ? "engine.zip" : "engine.tar.gz");
6827
6998
  ui.step(`Preparing the ${brand.displayName} engine (first run only)\u2026`);
6828
6999
  const resp = await fetch(url, {
6829
7000
  redirect: "follow",
@@ -6837,11 +7008,11 @@ async function ensureEngine() {
6837
7008
  `Could not download the engine (HTTP ${resp.status}). Check your connection and try again.`
6838
7009
  );
6839
7010
  }
6840
- await (0, import_promises3.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0, import_node_fs9.createWriteStream)(archivePath));
7011
+ await (0, import_promises3.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0, import_node_fs10.createWriteStream)(archivePath));
6841
7012
  if (artifact?.sha256) {
6842
7013
  const actual = await sha256File(archivePath);
6843
7014
  if (actual !== artifact.sha256) {
6844
- (0, import_node_fs9.rmSync)(archivePath, { force: true });
7015
+ (0, import_node_fs10.rmSync)(archivePath, { force: true });
6845
7016
  throw new ApiError(
6846
7017
  0,
6847
7018
  "engine_checksum_mismatch",
@@ -6850,7 +7021,7 @@ async function ensureEngine() {
6850
7021
  }
6851
7022
  }
6852
7023
  const extract = archivePath.endsWith(".zip") ? (0, import_node_child_process3.spawnSync)("unzip", ["-oq", archivePath], { cwd: dir, stdio: "ignore" }) : (0, import_node_child_process3.spawnSync)("tar", ["-xzf", archivePath], { cwd: dir, stdio: "ignore" });
6853
- (0, import_node_fs9.rmSync)(archivePath, { force: true });
7024
+ (0, import_node_fs10.rmSync)(archivePath, { force: true });
6854
7025
  if (extract.status !== 0) {
6855
7026
  throw new ApiError(
6856
7027
  0,
@@ -6858,24 +7029,24 @@ async function ensureEngine() {
6858
7029
  `Could not unpack the engine (needs ${archivePath.endsWith(".zip") ? "unzip" : "tar"} on PATH).`
6859
7030
  );
6860
7031
  }
6861
- const extracted = (0, import_node_path11.join)(dir, "opencode");
6862
- if ((0, import_node_fs9.existsSync)(extracted) && !(0, import_node_fs9.existsSync)(binPath)) (0, import_node_fs9.renameSync)(extracted, binPath);
6863
- if (!(0, import_node_fs9.existsSync)(binPath)) {
7032
+ const extracted = (0, import_node_path12.join)(dir, "opencode");
7033
+ if ((0, import_node_fs10.existsSync)(extracted) && !(0, import_node_fs10.existsSync)(binPath)) (0, import_node_fs10.renameSync)(extracted, binPath);
7034
+ if (!(0, import_node_fs10.existsSync)(binPath)) {
6864
7035
  throw new ApiError(0, "engine_extract_failed", "Engine archive did not contain the expected binary.");
6865
7036
  }
6866
- (0, import_node_fs9.chmodSync)(binPath, 493);
7037
+ (0, import_node_fs10.chmodSync)(binPath, 493);
6867
7038
  ui.ok(`Engine ready.`);
6868
7039
  console.log(paint.dim(" powered by opencode (MIT) \xB7 run `agentful licenses` for details"));
6869
7040
  return binPath;
6870
7041
  }
6871
7042
 
6872
7043
  // src/lib/gatewayToken.ts
6873
- var import_node_fs10 = require("fs");
6874
- var import_node_path12 = require("path");
6875
- var cachePath = () => (0, import_node_path12.join)(configDir(), "gateway.json");
7044
+ var import_node_fs11 = require("fs");
7045
+ var import_node_path13 = require("path");
7046
+ var cachePath = () => (0, import_node_path13.join)(configDir(), "gateway.json");
6876
7047
  async function ensureGatewaySession(auth, projectId) {
6877
7048
  try {
6878
- const cached = JSON.parse((0, import_node_fs10.readFileSync)(cachePath(), "utf8"));
7049
+ const cached = JSON.parse((0, import_node_fs11.readFileSync)(cachePath(), "utf8"));
6879
7050
  if (cached?.token && cached.expires_at - Date.now() / 1e3 > 3600) {
6880
7051
  return cached;
6881
7052
  }
@@ -6886,18 +7057,18 @@ async function ensureGatewaySession(auth, projectId) {
6886
7057
  body: projectId ? { project_id: projectId } : {},
6887
7058
  timeoutMs: 3e4
6888
7059
  });
6889
- (0, import_node_fs10.mkdirSync)(configDir(), { recursive: true });
6890
- (0, import_node_fs10.writeFileSync)(cachePath(), JSON.stringify(res, null, 2) + "\n", "utf8");
7060
+ (0, import_node_fs11.mkdirSync)(configDir(), { recursive: true });
7061
+ (0, import_node_fs11.writeFileSync)(cachePath(), JSON.stringify(res, null, 2) + "\n", "utf8");
6891
7062
  try {
6892
- (0, import_node_fs10.chmodSync)(cachePath(), 384);
7063
+ (0, import_node_fs11.chmodSync)(cachePath(), 384);
6893
7064
  } catch {
6894
7065
  }
6895
7066
  return res;
6896
7067
  }
6897
7068
 
6898
7069
  // src/lib/engineConfig.ts
6899
- var import_node_fs12 = require("fs");
6900
- var import_node_path14 = require("path");
7070
+ var import_node_fs13 = require("fs");
7071
+ var import_node_path15 = require("path");
6901
7072
  var import_node_os5 = require("os");
6902
7073
 
6903
7074
  // src/branding/agentful-theme.json
@@ -7040,22 +7211,22 @@ ${cmd.template}
7040
7211
  }
7041
7212
 
7042
7213
  // src/lib/tools.ts
7043
- var import_node_fs11 = require("fs");
7044
- var import_node_path13 = require("path");
7214
+ var import_node_fs12 = require("fs");
7215
+ var import_node_path14 = require("path");
7045
7216
  function assetsDir() {
7046
- const here = (0, import_node_path13.dirname)(process.argv[1] || "");
7047
- for (const candidate of [(0, import_node_path13.join)(here, "..", "assets"), (0, import_node_path13.join)(here, "assets")]) {
7048
- if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(candidate, "tools", "imagegen.ts"))) return candidate;
7217
+ const here = (0, import_node_path14.dirname)(process.argv[1] || "");
7218
+ for (const candidate of [(0, import_node_path14.join)(here, "..", "assets"), (0, import_node_path14.join)(here, "assets")]) {
7219
+ if ((0, import_node_fs12.existsSync)((0, import_node_path14.join)(candidate, "tools", "imagegen.ts"))) return candidate;
7049
7220
  }
7050
7221
  return null;
7051
7222
  }
7052
7223
  function installEngineTools(configDir2) {
7053
7224
  const assets = assetsDir();
7054
7225
  if (!assets) return false;
7055
- const target = (0, import_node_path13.join)(configDir2, "tools");
7056
- (0, import_node_fs11.mkdirSync)(target, { recursive: true });
7226
+ const target = (0, import_node_path14.join)(configDir2, "tools");
7227
+ (0, import_node_fs12.mkdirSync)(target, { recursive: true });
7057
7228
  try {
7058
- (0, import_node_fs11.cpSync)((0, import_node_path13.join)(assets, "tools"), target, { recursive: true });
7229
+ (0, import_node_fs12.cpSync)((0, import_node_path14.join)(assets, "tools"), target, { recursive: true });
7059
7230
  return true;
7060
7231
  } catch {
7061
7232
  return false;
@@ -7125,6 +7296,14 @@ function managedServerLine(backend) {
7125
7296
  const ownApi = backend.serverMode === "byo" ? "Server: the owner connected **an API of their own** \u2014 `/api/*` on the app's domain is forwarded to it, and the platform adds no secret and authorizes nobody. " : "";
7126
7297
  return `${ownApi}Managed server: **not switched on** in the Backend tab. **Action files you push are stored, but every call to them answers \`404 server_not_enabled\`** until the owner switches the managed server on (\`agentful backend\` opens the tab; the CLI can enable the database, NOT the server). Switching on takes effect on the next call. Never tell the user an action works before the server is on.`;
7127
7298
  }
7299
+ function buildEnvList() {
7300
+ const entries = contract_default.publish.build_env.injected;
7301
+ const when = {
7302
+ always: "always",
7303
+ byo_supabase: "only while the owner's own Supabase database is connected in the Backend tab"
7304
+ };
7305
+ return entries.map((e) => ` - ${e.prefixes.map((p) => `\`${p}${e.suffix}\``).join(", ")} \u2014 ${when[e.when] ?? e.when}`).join("\n");
7306
+ }
7128
7307
  var bytes = (n) => n >= 1024 * 1024 ? `${n / (1024 * 1024)} MB` : `${n / 1024} KB`;
7129
7308
  function serverSideSection() {
7130
7309
  const tracks = contract_default.server_side;
@@ -7180,18 +7359,26 @@ is fine \u2014 but then say clearly that \`agentful push\` cannot deploy it.
7180
7359
  Server-side logic has its own place \u2014 see "Where server logic belongs".
7181
7360
  - The canonical build output is a root-level \`index.html\` inside the
7182
7361
  framework's output directory.
7183
- - There are **no build-time env vars**: the cloud build injects nothing beyond
7184
- NODE_ENV. There is no settings tab for build secrets \u2014 do not invent one.
7185
- Backend-tab secrets are runtime-only for Managed Server Actions and never
7186
- reach a build; the workspace executor injects only allowlisted PUBLIC client
7187
- vars (\`database.anon_key\`/\`publishable_key\` expanded as
7188
- \`VITE_\`/\`PUBLIC_\`/\`NEXT_PUBLIC_\`). Never rely on \`.env*\` files reaching the
7189
- cloud \u2014 the CLI and server both strip them.
7190
- - So PUBLIC client values go into an ordinary source constant, not into
7191
- \`import.meta.env\`/\`process.env\`: the project ID (below) and, when the app
7192
- talks to the owner's own Supabase, its project URL and **publishable (anon)
7193
- key**. In an \`agentful push\` build \`import.meta.env.VITE_SUPABASE_URL\` is
7194
- \`undefined\` \u2014 the app would compile and then fail to reach its database.
7362
+ - You **cannot set build-time env vars**, and there is no settings tab for
7363
+ build secrets \u2014 do not invent one. Backend-tab secrets are runtime-only for
7364
+ Managed Server Actions and never reach a build. Every cloud build \u2014 the
7365
+ workspace build and the \`agentful push\` build alike \u2014 defines the same
7366
+ fixed allowlist of PUBLIC client values, and nothing else:
7367
+ ${buildEnvList()}
7368
+ Never rely on \`.env*\` files reaching the cloud \u2014 the CLI never uploads
7369
+ them.
7370
+ - A cloud build **rejects** a read of one of those names while nothing defines
7371
+ it (e.g. \`import.meta.env.VITE_SUPABASE_URL\` with no own Supabase database
7372
+ connected): it would compile to \`undefined\` without any build error and the
7373
+ app would fail to reach its database. A read of any OTHER
7374
+ \`VITE_\`/\`PUBLIC_\`/\`NEXT_PUBLIC_\` name is never defined by the platform; the
7375
+ build warns and inlines \`undefined\`.
7376
+ - So PUBLIC client values of your own go into an ordinary source constant, not
7377
+ into \`import.meta.env\`/\`process.env\`. For the project ID (below) and, when
7378
+ the app talks to the owner's own Supabase, its project URL and **publishable
7379
+ (anon) key**, a source constant is also the form that works in local
7380
+ development: on this machine nothing defines the names above unless the user
7381
+ keeps a local \`.env\`, which never leaves it.
7195
7382
  Never put a Supabase **secret / service-role key** in source: that one
7196
7383
  belongs in Backend-tab secrets and is only readable from a Managed Server
7197
7384
  Action.
@@ -7342,7 +7529,7 @@ var CLOUD_AGENT_PROMPT = `You are the Agentful Cloud build agent: everything you
7342
7529
  var LOCAL_AGENT_PROMPT = `You are in local-only mode: free local development with no cloud deployment target \u2014 any stack is fine. Be clear that this directory will NOT be deployable with \`agentful push\` unless it satisfies the platform contract in AGENTFUL_CLOUD.md (${SERVER_SIDE_IN_ONE_SENTENCE}). If the user asks to deploy or push, check the contract first and say honestly whether the project can ship on the platform; never claim cloud deployability without evidence.`;
7343
7530
  function readAuthFile(path) {
7344
7531
  try {
7345
- return (0, import_node_fs12.readFileSync)(path, "utf8");
7532
+ return (0, import_node_fs13.readFileSync)(path, "utf8");
7346
7533
  } catch {
7347
7534
  return null;
7348
7535
  }
@@ -7407,11 +7594,11 @@ function buildEngineConfig(opts) {
7407
7594
  };
7408
7595
  }
7409
7596
  function engineXdg() {
7410
- const root = (0, import_node_path14.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful");
7597
+ const root = (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful");
7411
7598
  return {
7412
- configHome: (0, import_node_path14.join)(root, "engine-config"),
7413
- dataHome: (0, import_node_path14.join)(root, "engine-data"),
7414
- stateHome: (0, import_node_path14.join)(root, "engine-state")
7599
+ configHome: (0, import_node_path15.join)(root, "engine-config"),
7600
+ dataHome: (0, import_node_path15.join)(root, "engine-data"),
7601
+ stateHome: (0, import_node_path15.join)(root, "engine-state")
7415
7602
  };
7416
7603
  }
7417
7604
  async function resolveTheme() {
@@ -7430,24 +7617,24 @@ async function resolveTheme() {
7430
7617
  }
7431
7618
  async function writeEngineSession(session, catalog, localProviders = {}, framework = "unknown", skillsInstruction = null, backendState, model) {
7432
7619
  const xdg = engineXdg();
7433
- const configDir2 = (0, import_node_path14.join)(xdg.configHome, "opencode");
7434
- const dataDir = (0, import_node_path14.join)(xdg.dataHome, "opencode");
7435
- const themesDir = (0, import_node_path14.join)(configDir2, "themes");
7436
- const pluginsDir = (0, import_node_path14.join)(configDir2, "plugins");
7437
- const commandsDir = (0, import_node_path14.join)(configDir2, "commands");
7438
- for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0, import_node_path14.join)(xdg.stateHome, "opencode")]) {
7439
- (0, import_node_fs12.mkdirSync)(dir, { recursive: true });
7620
+ const configDir2 = (0, import_node_path15.join)(xdg.configHome, "opencode");
7621
+ const dataDir = (0, import_node_path15.join)(xdg.dataHome, "opencode");
7622
+ const themesDir = (0, import_node_path15.join)(configDir2, "themes");
7623
+ const pluginsDir = (0, import_node_path15.join)(configDir2, "plugins");
7624
+ const commandsDir = (0, import_node_path15.join)(configDir2, "commands");
7625
+ for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0, import_node_path15.join)(xdg.stateHome, "opencode")]) {
7626
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
7440
7627
  }
7441
7628
  const imagegenAvailable = installEngineTools(configDir2) && session.img_on !== false;
7442
- const cloudInstructionsPath = (0, import_node_path14.join)(configDir2, CLOUD_INSTRUCTIONS_FILENAME);
7443
- (0, import_node_fs12.writeFileSync)(cloudInstructionsPath, renderCloudInstructions(framework, backendState));
7444
- const skillsPath = (0, import_node_path14.join)(configDir2, "AGENTFUL_SKILLS.md");
7629
+ const cloudInstructionsPath = (0, import_node_path15.join)(configDir2, CLOUD_INSTRUCTIONS_FILENAME);
7630
+ (0, import_node_fs13.writeFileSync)(cloudInstructionsPath, renderCloudInstructions(framework, backendState));
7631
+ const skillsPath = (0, import_node_path15.join)(configDir2, "AGENTFUL_SKILLS.md");
7445
7632
  const instructionPaths = [cloudInstructionsPath];
7446
7633
  if (skillsInstruction) {
7447
- (0, import_node_fs12.writeFileSync)(skillsPath, skillsInstruction);
7634
+ (0, import_node_fs13.writeFileSync)(skillsPath, skillsInstruction);
7448
7635
  instructionPaths.push(skillsPath);
7449
7636
  } else {
7450
- (0, import_node_fs12.rmSync)(skillsPath, { force: true });
7637
+ (0, import_node_fs13.rmSync)(skillsPath, { force: true });
7451
7638
  }
7452
7639
  const config = buildEngineConfig({
7453
7640
  session,
@@ -7457,13 +7644,13 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
7457
7644
  instructionPaths,
7458
7645
  model
7459
7646
  });
7460
- (0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(configDir2, "config.json"), JSON.stringify(config, null, 2));
7461
- const authPath2 = (0, import_node_path14.join)(dataDir, "auth.json");
7462
- (0, import_node_fs12.writeFileSync)(authPath2, mergedAuthJson(readAuthFile(authPath2), session.token));
7647
+ (0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(configDir2, "config.json"), JSON.stringify(config, null, 2));
7648
+ const authPath2 = (0, import_node_path15.join)(dataDir, "auth.json");
7649
+ (0, import_node_fs13.writeFileSync)(authPath2, mergedAuthJson(readAuthFile(authPath2), session.token));
7463
7650
  const { brandingPluginSource: brandingPluginSource2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
7464
- const pluginPath = (0, import_node_path14.join)(pluginsDir, "agentful-branding.tsx");
7465
- (0, import_node_fs12.writeFileSync)(pluginPath, brandingPluginSource2());
7466
- (0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(configDir2, "tui.json"), JSON.stringify({
7651
+ const pluginPath = (0, import_node_path15.join)(pluginsDir, "agentful-branding.tsx");
7652
+ (0, import_node_fs13.writeFileSync)(pluginPath, brandingPluginSource2());
7653
+ (0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(configDir2, "tui.json"), JSON.stringify({
7467
7654
  theme: "agentful",
7468
7655
  plugin: [`file://${pluginPath}`],
7469
7656
  // The engine's own sidebar sections are plugins with fixed ids, and
@@ -7475,13 +7662,13 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
7475
7662
  // state over this map.
7476
7663
  plugin_enabled: DISABLED_ENGINE_PLUGINS
7477
7664
  }, null, 2));
7478
- (0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(themesDir, "agentful.json"), JSON.stringify(await resolveTheme(), null, 2));
7665
+ (0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(themesDir, "agentful.json"), JSON.stringify(await resolveTheme(), null, 2));
7479
7666
  for (const name of Object.keys(SLASH_COMMANDS)) {
7480
- (0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(commandsDir, `${name}.md`), commandMarkdown(name));
7667
+ (0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(commandsDir, `${name}.md`), commandMarkdown(name));
7481
7668
  }
7482
7669
  for (const legacy of ["xdg-config", "xdg-data", "xdg-state"]) {
7483
7670
  try {
7484
- (0, import_node_fs12.rmSync)((0, import_node_path14.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful", legacy), { recursive: true, force: true });
7671
+ (0, import_node_fs13.rmSync)((0, import_node_path15.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful", legacy), { recursive: true, force: true });
7485
7672
  } catch {
7486
7673
  }
7487
7674
  }
@@ -7489,8 +7676,8 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
7489
7676
  }
7490
7677
 
7491
7678
  // src/lib/skills.ts
7492
- var import_node_fs13 = require("fs");
7493
- var import_node_path15 = require("path");
7679
+ var import_node_fs14 = require("fs");
7680
+ var import_node_path16 = require("path");
7494
7681
 
7495
7682
  // src/generated/skills.json
7496
7683
  var skills_default = {
@@ -7559,7 +7746,7 @@ var SCAFFOLD_BY_FRAMEWORK = {
7559
7746
  };
7560
7747
  function hasVueDependency(rootDir) {
7561
7748
  try {
7562
- const pkg = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path15.join)(rootDir, "package.json"), "utf8"));
7749
+ const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path16.join)(rootDir, "package.json"), "utf8"));
7563
7750
  return Boolean({ ...pkg.dependencies, ...pkg.devDependencies }["vue"]);
7564
7751
  } catch {
7565
7752
  return false;
@@ -7589,7 +7776,7 @@ function renderSkillsInstruction(names) {
7589
7776
  return "# Platform deployment skills (mandatory)\n\nThese are the same skills the cloud build agent loads for this stack.\nFollow them when scaffolding or editing \u2014 they are not optional hints.\n\n" + sections.join("\n\n---\n\n") + "\n";
7590
7777
  }
7591
7778
  function skillsInstructionFor(framework, rootDir) {
7592
- if (!(0, import_node_fs13.existsSync)(rootDir)) return null;
7779
+ if (!(0, import_node_fs14.existsSync)(rootDir)) return null;
7593
7780
  return renderSkillsInstruction(selectSkills(framework, rootDir));
7594
7781
  }
7595
7782
 
@@ -7737,15 +7924,15 @@ function decideLocalProviders(policy) {
7737
7924
  }
7738
7925
 
7739
7926
  // src/lib/localProviders.ts
7740
- var import_node_fs14 = require("fs");
7741
- var import_node_path16 = require("path");
7927
+ var import_node_fs15 = require("fs");
7928
+ var import_node_path17 = require("path");
7742
7929
  var LOCAL_PROVIDERS_FILE = "local-providers.json";
7743
7930
  function localProvidersPath() {
7744
- return (0, import_node_path16.join)(configDir(), LOCAL_PROVIDERS_FILE);
7931
+ return (0, import_node_path17.join)(configDir(), LOCAL_PROVIDERS_FILE);
7745
7932
  }
7746
7933
  function readLocalProviders() {
7747
7934
  try {
7748
- const raw = JSON.parse((0, import_node_fs14.readFileSync)(localProvidersPath(), "utf8"));
7935
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(localProvidersPath(), "utf8"));
7749
7936
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
7750
7937
  const map = raw.providers && typeof raw.providers === "object" ? raw.providers : raw;
7751
7938
  const usable = {};
@@ -7780,8 +7967,8 @@ function resolveLocalProviders(policy) {
7780
7967
  }
7781
7968
  function writeLocalProvidersExample() {
7782
7969
  const path = localProvidersPath();
7783
- if ((0, import_node_fs14.existsSync)(path)) return path;
7784
- (0, import_node_fs14.mkdirSync)(configDir(), { recursive: true });
7970
+ if ((0, import_node_fs15.existsSync)(path)) return path;
7971
+ (0, import_node_fs15.mkdirSync)(configDir(), { recursive: true });
7785
7972
  const example = {
7786
7973
  _comment: 'Providers with your own API key, running locally. Requests go directly to the provider \u2014 no Agentful credits, no platform region guarantee. Remove the leading underscore from "_anthropic" and fill in your key to enable it.',
7787
7974
  _anthropic: {
@@ -7791,17 +7978,17 @@ function writeLocalProvidersExample() {
7791
7978
  models: { "claude-sonnet-4-5": { name: "Claude Sonnet 4.5 (my key)" } }
7792
7979
  }
7793
7980
  };
7794
- (0, import_node_fs14.writeFileSync)(path, JSON.stringify(example, null, 2) + "\n", "utf8");
7981
+ (0, import_node_fs15.writeFileSync)(path, JSON.stringify(example, null, 2) + "\n", "utf8");
7795
7982
  try {
7796
- (0, import_node_fs14.chmodSync)(path, 384);
7983
+ (0, import_node_fs15.chmodSync)(path, 384);
7797
7984
  } catch {
7798
7985
  }
7799
7986
  return path;
7800
7987
  }
7801
7988
 
7802
7989
  // src/lib/sessions.ts
7803
- var import_node_fs15 = require("fs");
7804
- var import_node_path17 = require("path");
7990
+ var import_node_fs16 = require("fs");
7991
+ var import_node_path18 = require("path");
7805
7992
  var import_node_child_process4 = require("child_process");
7806
7993
  function parseSessionModel(raw) {
7807
7994
  if (!raw) return null;
@@ -7818,8 +8005,8 @@ function parseSessionModel(raw) {
7818
8005
  }
7819
8006
  }
7820
8007
  function modelForSession(sessionID) {
7821
- const dbPath = (0, import_node_path17.join)(engineXdg().dataHome, "opencode", "opencode.db");
7822
- if (!(0, import_node_fs15.existsSync)(dbPath)) return null;
8008
+ const dbPath = (0, import_node_path18.join)(engineXdg().dataHome, "opencode", "opencode.db");
8009
+ if (!(0, import_node_fs16.existsSync)(dbPath)) return null;
7823
8010
  const escaped = sessionID.replace(/'/g, "''");
7824
8011
  const res = (0, import_node_child_process4.spawnSync)(
7825
8012
  "sqlite3",
@@ -7840,8 +8027,8 @@ function modelForSession(sessionID) {
7840
8027
  }
7841
8028
  }
7842
8029
  function lastSessionForDirectory(cwd = process.cwd()) {
7843
- const dbPath = (0, import_node_path17.join)(engineXdg().dataHome, "opencode", "opencode.db");
7844
- if (!(0, import_node_fs15.existsSync)(dbPath)) return null;
8030
+ const dbPath = (0, import_node_path18.join)(engineXdg().dataHome, "opencode", "opencode.db");
8031
+ if (!(0, import_node_fs16.existsSync)(dbPath)) return null;
7845
8032
  const escaped = cwd.replace(/'/g, "''");
7846
8033
  const res = (0, import_node_child_process4.spawnSync)(
7847
8034
  "sqlite3",
@@ -7867,9 +8054,9 @@ function lastSessionForDirectory(cwd = process.cwd()) {
7867
8054
  }
7868
8055
 
7869
8056
  // src/lib/modelPin.ts
7870
- var import_node_fs16 = require("fs");
7871
- var import_node_path18 = require("path");
7872
- var PROJECT_MODEL_PIN = (0, import_node_path18.join)(".agentful", "model.json");
8057
+ var import_node_fs17 = require("fs");
8058
+ var import_node_path19 = require("path");
8059
+ var PROJECT_MODEL_PIN = (0, import_node_path19.join)(".agentful", "model.json");
7873
8060
  function isCanonicalModel(value) {
7874
8061
  const slash = value.indexOf("/");
7875
8062
  return slash > 0 && slash < value.length - 1 && !/\s/.test(value);
@@ -7889,10 +8076,10 @@ function assertModelPin(pin, source) {
7889
8076
  return pin;
7890
8077
  }
7891
8078
  function readProjectModelPin(cwd = process.cwd()) {
7892
- const path = (0, import_node_path18.join)(cwd, PROJECT_MODEL_PIN);
8079
+ const path = (0, import_node_path19.join)(cwd, PROJECT_MODEL_PIN);
7893
8080
  let raw;
7894
8081
  try {
7895
- raw = (0, import_node_fs16.readFileSync)(path, "utf8");
8082
+ raw = (0, import_node_fs17.readFileSync)(path, "utf8");
7896
8083
  } catch (error) {
7897
8084
  const code = error.code;
7898
8085
  if (code === "ENOENT") return null;
@@ -7919,7 +8106,7 @@ function readProjectModelPin(cwd = process.cwd()) {
7919
8106
  function readEngineVariants(xdg) {
7920
8107
  try {
7921
8108
  const parsed = JSON.parse(
7922
- (0, import_node_fs16.readFileSync)((0, import_node_path18.join)(xdg.stateHome, "opencode", "model.json"), "utf8")
8109
+ (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(xdg.stateHome, "opencode", "model.json"), "utf8")
7923
8110
  );
7924
8111
  if (!parsed.variant || typeof parsed.variant !== "object" || Array.isArray(parsed.variant)) return {};
7925
8112
  return Object.fromEntries(
@@ -7931,17 +8118,17 @@ function readEngineVariants(xdg) {
7931
8118
  }
7932
8119
  function writeEngineVariant(xdg, model, variant) {
7933
8120
  assertModelPin({ model, variant }, "Selected");
7934
- const path = (0, import_node_path18.join)(xdg.stateHome, "opencode", "model.json");
8121
+ const path = (0, import_node_path19.join)(xdg.stateHome, "opencode", "model.json");
7935
8122
  let state = {};
7936
8123
  try {
7937
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
8124
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
7938
8125
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) state = parsed;
7939
8126
  } catch {
7940
8127
  }
7941
8128
  const existing = state.variant;
7942
8129
  const variants = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
7943
8130
  state.variant = { ...variants, [model]: variant };
7944
- (0, import_node_fs16.writeFileSync)(path, JSON.stringify(state, null, 2) + "\n", "utf8");
8131
+ (0, import_node_fs17.writeFileSync)(path, JSON.stringify(state, null, 2) + "\n", "utf8");
7945
8132
  }
7946
8133
  function resolveModelPin(opts) {
7947
8134
  const cliPin = opts.cliModel ? assertModelPin({ model: opts.cliModel, variant: opts.cliVariant }, "CLI") : null;
@@ -7990,8 +8177,8 @@ function resolveModelPin(opts) {
7990
8177
  // src/lib/engineModels.ts
7991
8178
  var import_node_child_process5 = require("child_process");
7992
8179
  var import_node_util = require("util");
7993
- var import_node_fs17 = require("fs");
7994
- var import_node_path19 = require("path");
8180
+ var import_node_fs18 = require("fs");
8181
+ var import_node_path20 = require("path");
7995
8182
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process5.execFile);
7996
8183
  function parseEngineModelsOutput(output) {
7997
8184
  return Array.from(new Set(
@@ -8042,7 +8229,7 @@ async function assertEngineModelAvailable(binPath, xdg, model, listModels = list
8042
8229
  function readConnectedEngineProviders(xdg) {
8043
8230
  try {
8044
8231
  const parsed = JSON.parse(
8045
- (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(xdg.dataHome, "opencode", "auth.json"), "utf8")
8232
+ (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(xdg.dataHome, "opencode", "auth.json"), "utf8")
8046
8233
  );
8047
8234
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
8048
8235
  return Object.keys(parsed).filter((id) => id !== "agentful").sort();
@@ -8470,7 +8657,7 @@ async function tuiCommand(opts = {}) {
8470
8657
  ...process.env,
8471
8658
  // Slash commands run `agentful …` through the agent's bash tool, which
8472
8659
  // has no access to the user's shell aliases.
8473
- PATH: `${binDir}${import_node_path20.delimiter}${process.env.PATH || ""}`,
8660
+ PATH: `${binDir}${import_node_path21.delimiter}${process.env.PATH || ""}`,
8474
8661
  XDG_CONFIG_HOME: xdg.configHome,
8475
8662
  XDG_DATA_HOME: xdg.dataHome,
8476
8663
  XDG_STATE_HOME: xdg.stateHome,
@@ -8601,38 +8788,38 @@ async function shareCommand(opts) {
8601
8788
  }
8602
8789
 
8603
8790
  // src/commands/pull.ts
8604
- var import_node_fs19 = require("fs");
8605
- var import_node_path22 = require("path");
8791
+ var import_node_fs20 = require("fs");
8792
+ var import_node_path23 = require("path");
8606
8793
  init_branding();
8607
8794
  init_branding();
8608
8795
 
8609
8796
  // src/lib/pullFiles.ts
8610
- var import_node_fs18 = require("fs");
8611
- var import_node_path21 = require("path");
8797
+ var import_node_fs19 = require("fs");
8798
+ var import_node_path22 = require("path");
8612
8799
  var INLINE_BASE64_EXTENSIONS = /\.(?:png|jpe?g|gif|webp|avif|svg|ico|bmp|tiff?|woff2?|ttf|otf|eot|pdf|docx?|xlsx?|pptx?|zip|tar|gz|7z|rar|bz2|mp[34]|m4a|wav|ogg|avi|mov|mkv|flac|webm|exe|dll|so|dylib|bin|wasm)$/i;
8613
8800
  function inlineContent(value) {
8614
8801
  return typeof value === "object" && value !== null && "content" in value ? String(value.content) : String(value ?? "");
8615
8802
  }
8616
8803
  function writePulledWorkspaceEntry(root, rel, value) {
8617
- const target = (0, import_node_path21.join)(root, rel);
8618
- (0, import_node_fs18.mkdirSync)((0, import_node_path21.dirname)(target), { recursive: true });
8804
+ const target = (0, import_node_path22.join)(root, rel);
8805
+ (0, import_node_fs19.mkdirSync)((0, import_node_path22.dirname)(target), { recursive: true });
8619
8806
  const content = inlineContent(value);
8620
8807
  if (INLINE_BASE64_EXTENSIONS.test(rel)) {
8621
- (0, import_node_fs18.writeFileSync)(target, Buffer.from(content, "base64"));
8808
+ (0, import_node_fs19.writeFileSync)(target, Buffer.from(content, "base64"));
8622
8809
  return;
8623
8810
  }
8624
- (0, import_node_fs18.writeFileSync)(target, content, "utf8");
8811
+ (0, import_node_fs19.writeFileSync)(target, content, "utf8");
8625
8812
  }
8626
8813
  function writePulledBackendDeclaration(root, declaration) {
8627
- const target = (0, import_node_path21.join)(root, ".agentful", "backend.json");
8628
- (0, import_node_fs18.mkdirSync)((0, import_node_path21.dirname)(target), { recursive: true });
8814
+ const target = (0, import_node_path22.join)(root, ".agentful", "backend.json");
8815
+ (0, import_node_fs19.mkdirSync)((0, import_node_path22.dirname)(target), { recursive: true });
8629
8816
  const {
8630
8817
  source: _source,
8631
8818
  received_at: _receivedAt,
8632
8819
  last_sync: _lastSync,
8633
8820
  ...portableDeclaration
8634
8821
  } = declaration;
8635
- (0, import_node_fs18.writeFileSync)(target, `${JSON.stringify(portableDeclaration, null, 2)}
8822
+ (0, import_node_fs19.writeFileSync)(target, `${JSON.stringify(portableDeclaration, null, 2)}
8636
8823
  `, "utf8");
8637
8824
  }
8638
8825
 
@@ -8641,7 +8828,7 @@ async function pullCommand(opts) {
8641
8828
  console.log(banner());
8642
8829
  const auth = await ensureAuth();
8643
8830
  const project = requireProject();
8644
- const nonHidden = (0, import_node_fs19.readdirSync)(process.cwd()).filter((n) => n !== ".agentful" && !n.startsWith("."));
8831
+ const nonHidden = (0, import_node_fs20.readdirSync)(process.cwd()).filter((n) => n !== ".agentful" && !n.startsWith("."));
8645
8832
  if (nonHidden.length > 0 && !opts.force) {
8646
8833
  throw new ApiError(
8647
8834
  0,
@@ -8668,9 +8855,9 @@ async function pullCommand(opts) {
8668
8855
  ui.warn(`Skipped ${rel} (HTTP ${resp.status})`);
8669
8856
  continue;
8670
8857
  }
8671
- const target = (0, import_node_path22.join)(process.cwd(), rel);
8672
- (0, import_node_fs19.mkdirSync)((0, import_node_path22.dirname)(target), { recursive: true });
8673
- (0, import_node_fs19.writeFileSync)(target, Buffer.from(await resp.arrayBuffer()));
8858
+ const target = (0, import_node_path23.join)(process.cwd(), rel);
8859
+ (0, import_node_fs20.mkdirSync)((0, import_node_path23.dirname)(target), { recursive: true });
8860
+ (0, import_node_fs20.writeFileSync)(target, Buffer.from(await resp.arrayBuffer()));
8674
8861
  written++;
8675
8862
  }
8676
8863
  } else if (data.files) {