agentful 0.4.5 → 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/README.md +15 -3
- package/dist/index.cjs +394 -202
- package/package.json +1 -1
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/example.d.ts +0 -2
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/example.js +0 -16
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/index.d.ts +0 -267
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/index.js +0 -1
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/shell.d.ts +0 -109
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/shell.js +0 -1
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/tool.d.ts +0 -46
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/tool.js +0 -5
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/tui.d.ts +0 -429
- package/assets/tools/node_modules/@opencode-ai/plugin/dist/tui.js +0 -1
- package/assets/tools/node_modules/@opencode-ai/plugin/package.json +0 -52
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.
|
|
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
|
|
5601
|
-
var
|
|
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:
|
|
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
|
|
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)."
|
|
@@ -5618,10 +5628,11 @@ var contract_default = {
|
|
|
5618
5628
|
$comment_limits: "Compressed zip bytes. Enforced server-side as MAX_TEMPLATE_ZIP_UPLOAD_BYTES (aws-services/workspace-manager/handler.py); ~8 MB as base64, under the API Gateway 10 MB request cap."
|
|
5619
5629
|
},
|
|
5620
5630
|
server_side: {
|
|
5621
|
-
$comment: "What 'server' means on this platform (server-option plan 2026-09-18, AP2). THREE separate tracks with separate limits \u2014 never quote one track's limits for another. managed_actions.limits is pinned against the source constants by check-parity.py (check 10) and against the agent instructions (check 11); the behaviour behind action_timeout_budget_s is pinned in aws-services/action-runner/tests/sandbox_contract.test.js. Additive block: no schema_version bump.",
|
|
5631
|
+
$comment: "What 'server' means on this platform (server-option plan 2026-09-18, AP2). THREE separate tracks with separate limits \u2014 never quote one track's limits for another. managed_actions.limits is pinned against the source constants by check-parity.py (check 10) and against the agent instructions (check 11); the behaviour behind action_timeout_budget_s is pinned in aws-services/action-runner/tests/sandbox_contract.test.js, the one behind switch_off_delay_s (and the refusal itself) in tests/server_switch.test.js. The switch is enforced only while infrastructure/lib/s3-lambda-stack.ts says SERVER_SWITCH_ENFORCEMENT 'enforce' \u2014 check 12 fails if switch_note promises it under any other mode. Additive block: no schema_version bump.",
|
|
5622
5632
|
managed_actions: {
|
|
5623
5633
|
label: "Managed Server Actions",
|
|
5624
5634
|
summary: "Short request/response functions the platform runs for the project. One file is one endpoint; JSON in, JSON out. Backend tab: Server \u2192 Managed.",
|
|
5635
|
+
switch_note: 'Actions run only while the managed server is switched on in the Backend tab (Server \u2192 Managed). A managed database alone does not switch it on. While it is off, every action of the project answers 404 server_not_enabled. Switching on takes effect on the next call; switching off takes effect after the switch-off delay given under Limits at the latest, because warm instances remember "on" for that long. Storing is not running: uploading or pushing action files is not gated by the switch.',
|
|
5625
5636
|
offers: [
|
|
5626
5637
|
"One file = one endpoint: .server/actions/<name>.js is served at /api/p/{projectId}/actions/{name}, any HTTP method, JSON in, JSON out",
|
|
5627
5638
|
"Runtime secrets that never reach the browser: await ctx.secrets.get('server.<name>')",
|
|
@@ -5674,7 +5685,8 @@ var contract_default = {
|
|
|
5674
5685
|
max_body_bytes: 1048576,
|
|
5675
5686
|
max_code_bytes: 262144,
|
|
5676
5687
|
project_concurrency: 10,
|
|
5677
|
-
max_action_depth: 5
|
|
5688
|
+
max_action_depth: 5,
|
|
5689
|
+
switch_off_delay_s: 60
|
|
5678
5690
|
},
|
|
5679
5691
|
limits_note: "The per-action budget is a figure to plan with, not a guaranteed stop: an action still waiting on ctx.fetch or ctx.data when the budget runs out is answered with 408 timeout, synchronous code runs on until the hard limit, and after a 408 the action may still complete calls it had already started. Build actions so that a repeated call ends in the same state."
|
|
5680
5692
|
},
|
|
@@ -5804,7 +5816,7 @@ var contract_default = {
|
|
|
5804
5816
|
build_attempt_schema: {
|
|
5805
5817
|
file: "deployments/latest-build.json",
|
|
5806
5818
|
status_values: ["running", "success", "failed"],
|
|
5807
|
-
phase_codes: ["unsupported_project_type", "install", "build", "missing_output", "upload"],
|
|
5819
|
+
phase_codes: ["unsupported_project_type", "client_env", "install", "build", "missing_output", "upload"],
|
|
5808
5820
|
fields: {
|
|
5809
5821
|
schema_version: "int \u2014 copy of this contract's schema_version",
|
|
5810
5822
|
build_id: "string \u2014 unique per attempt",
|
|
@@ -5824,6 +5836,154 @@ var contract_default = {
|
|
|
5824
5836
|
}
|
|
5825
5837
|
};
|
|
5826
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
|
+
|
|
5827
5987
|
// src/lib/preflight.ts
|
|
5828
5988
|
function feature(id) {
|
|
5829
5989
|
const found = contract_default.forbidden_server_features.find((f) => f.id === id);
|
|
@@ -5851,14 +6011,14 @@ var STATIC_EXPORT = /output\s*:\s*['"]export['"]/;
|
|
|
5851
6011
|
var SOURCE_FILE = /\.(js|jsx|ts|tsx|mjs)$/;
|
|
5852
6012
|
var GET_SERVER_SIDE_PROPS = /export\s+(?:async\s+)?(?:function|const|let|var)\s+getServerSideProps\b|export\s*\{[^}]*\bgetServerSideProps\b[^}]*\}/;
|
|
5853
6013
|
var USE_SERVER = /^\s*(['"])use server\1\s*;?\s*$/m;
|
|
5854
|
-
var
|
|
5855
|
-
var
|
|
6014
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", "out"]);
|
|
6015
|
+
var SCAN_FILE_BUDGET2 = 5e3;
|
|
5856
6016
|
function detectFramework(rootDir) {
|
|
5857
|
-
const pkgPath = (0,
|
|
5858
|
-
if (!(0,
|
|
6017
|
+
const pkgPath = (0, import_node_path8.join)(rootDir, "package.json");
|
|
6018
|
+
if (!(0, import_node_fs6.existsSync)(pkgPath)) return "vanilla";
|
|
5859
6019
|
let pkg;
|
|
5860
6020
|
try {
|
|
5861
|
-
pkg = JSON.parse((0,
|
|
6021
|
+
pkg = JSON.parse((0, import_node_fs6.readFileSync)(pkgPath, "utf8"));
|
|
5862
6022
|
} catch {
|
|
5863
6023
|
return "unknown";
|
|
5864
6024
|
}
|
|
@@ -5868,32 +6028,32 @@ function detectFramework(rootDir) {
|
|
|
5868
6028
|
}
|
|
5869
6029
|
function readDeps(rootDir) {
|
|
5870
6030
|
try {
|
|
5871
|
-
const pkg = JSON.parse((0,
|
|
6031
|
+
const pkg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path8.join)(rootDir, "package.json"), "utf8"));
|
|
5872
6032
|
return { ...pkg.dependencies, ...pkg.devDependencies };
|
|
5873
6033
|
} catch {
|
|
5874
6034
|
return {};
|
|
5875
6035
|
}
|
|
5876
6036
|
}
|
|
5877
6037
|
function findFiles(rootDir, dir, pattern, out, cap = 20) {
|
|
5878
|
-
if (out.length >= cap || !(0,
|
|
5879
|
-
for (const entry of (0,
|
|
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 })) {
|
|
5880
6040
|
if (out.length >= cap) return;
|
|
5881
|
-
const abs = (0,
|
|
6041
|
+
const abs = (0, import_node_path8.join)(dir, entry.name);
|
|
5882
6042
|
if (entry.isDirectory()) {
|
|
5883
|
-
if (!
|
|
6043
|
+
if (!SKIP_DIRS2.has(entry.name)) findFiles(rootDir, abs, pattern, out, cap);
|
|
5884
6044
|
} else if (entry.isFile() && pattern.test(entry.name)) {
|
|
5885
|
-
out.push((0,
|
|
6045
|
+
out.push((0, import_node_path8.relative)(rootDir, abs).split(import_node_path8.sep).join("/"));
|
|
5886
6046
|
}
|
|
5887
6047
|
}
|
|
5888
6048
|
}
|
|
5889
6049
|
var sample = (list) => list.slice(0, 3).join(", ") + (list.length > 3 ? ", \u2026" : "");
|
|
5890
6050
|
function collectSourceFiles(dir, out, budget) {
|
|
5891
|
-
if (budget.left <= 0 || !(0,
|
|
5892
|
-
for (const entry of (0,
|
|
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 })) {
|
|
5893
6053
|
if (budget.left <= 0) return;
|
|
5894
|
-
const abs = (0,
|
|
6054
|
+
const abs = (0, import_node_path8.join)(dir, entry.name);
|
|
5895
6055
|
if (entry.isDirectory()) {
|
|
5896
|
-
if (!
|
|
6056
|
+
if (!SKIP_DIRS2.has(entry.name)) collectSourceFiles(abs, out, budget);
|
|
5897
6057
|
} else if (entry.isFile() && SOURCE_FILE.test(entry.name)) {
|
|
5898
6058
|
budget.left--;
|
|
5899
6059
|
out.push(abs);
|
|
@@ -5903,10 +6063,10 @@ function collectSourceFiles(dir, out, budget) {
|
|
|
5903
6063
|
function checkNextjs(rootDir) {
|
|
5904
6064
|
const issues = [];
|
|
5905
6065
|
const warnings = [];
|
|
5906
|
-
const configName = NEXT_CONFIG_BASENAMES.find((name) => (0,
|
|
6066
|
+
const configName = NEXT_CONFIG_BASENAMES.find((name) => (0, import_node_fs6.existsSync)((0, import_node_path8.join)(rootDir, name)));
|
|
5907
6067
|
let hasStaticExport = true;
|
|
5908
6068
|
if (configName) {
|
|
5909
|
-
const config = (0,
|
|
6069
|
+
const config = (0, import_node_fs6.readFileSync)((0, import_node_path8.join)(rootDir, configName), "utf8");
|
|
5910
6070
|
hasStaticExport = STATIC_EXPORT.test(config);
|
|
5911
6071
|
if (!hasStaticExport) {
|
|
5912
6072
|
issues.push(
|
|
@@ -5920,31 +6080,31 @@ function checkNextjs(rootDir) {
|
|
|
5920
6080
|
const hard = [];
|
|
5921
6081
|
const pagesApi = [];
|
|
5922
6082
|
for (const apiDir of PAGES_API_DIRS) {
|
|
5923
|
-
findFiles(rootDir, (0,
|
|
6083
|
+
findFiles(rootDir, (0, import_node_path8.join)(rootDir, apiDir), /\.(js|ts|jsx|tsx|mjs)$/, pagesApi);
|
|
5924
6084
|
}
|
|
5925
6085
|
if (pagesApi.length > 0) hard.push(`pages/api/* routes (${pagesApi.length} file(s))`);
|
|
5926
6086
|
const middlewareFiles = [];
|
|
5927
6087
|
for (const base of ["", "src"]) {
|
|
5928
|
-
const dir = base ? (0,
|
|
5929
|
-
if (!(0,
|
|
5930
|
-
for (const entry of (0,
|
|
5931
|
-
if (MIDDLEWARE_FILE.test(entry)) middlewareFiles.push((0,
|
|
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("/"));
|
|
5932
6092
|
}
|
|
5933
6093
|
}
|
|
5934
6094
|
hard.push(...middlewareFiles);
|
|
5935
6095
|
const sourceFiles = [];
|
|
5936
|
-
collectSourceFiles(rootDir, sourceFiles, { left:
|
|
6096
|
+
collectSourceFiles(rootDir, sourceFiles, { left: SCAN_FILE_BUDGET2 });
|
|
5937
6097
|
const gssp = [];
|
|
5938
6098
|
const useServer = [];
|
|
5939
6099
|
for (const abs of sourceFiles) {
|
|
5940
6100
|
if (gssp.length >= 20 && useServer.length >= 20) break;
|
|
5941
6101
|
let text;
|
|
5942
6102
|
try {
|
|
5943
|
-
text = (0,
|
|
6103
|
+
text = (0, import_node_fs6.readFileSync)(abs, "utf8");
|
|
5944
6104
|
} catch {
|
|
5945
6105
|
continue;
|
|
5946
6106
|
}
|
|
5947
|
-
const rel = (0,
|
|
6107
|
+
const rel = (0, import_node_path8.relative)(rootDir, abs).split(import_node_path8.sep).join("/");
|
|
5948
6108
|
if (gssp.length < 20 && GET_SERVER_SIDE_PROPS.test(text)) gssp.push(rel);
|
|
5949
6109
|
if (useServer.length < 20 && USE_SERVER.test(text)) useServer.push(rel);
|
|
5950
6110
|
}
|
|
@@ -5952,7 +6112,7 @@ function checkNextjs(rootDir) {
|
|
|
5952
6112
|
if (useServer.length > 0) hard.push(`'use server' actions (${sample(useServer)})`);
|
|
5953
6113
|
const routeFiles = [];
|
|
5954
6114
|
for (const appDir of APP_DIRS) {
|
|
5955
|
-
findFiles(rootDir, (0,
|
|
6115
|
+
findFiles(rootDir, (0, import_node_path8.join)(rootDir, appDir), ROUTE_HANDLER_FILE, routeFiles);
|
|
5956
6116
|
}
|
|
5957
6117
|
if (routeFiles.length > 0) {
|
|
5958
6118
|
const label = `${routeFiles.length} route handler(s) (${sample(routeFiles)})`;
|
|
@@ -5986,6 +6146,17 @@ function checkNextjs(rootDir) {
|
|
|
5986
6146
|
}
|
|
5987
6147
|
return { issues, warnings };
|
|
5988
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
|
+
}
|
|
5989
6160
|
function runPreflight(rootDir) {
|
|
5990
6161
|
const framework = detectFramework(rootDir);
|
|
5991
6162
|
const issues = [];
|
|
@@ -6000,17 +6171,18 @@ function runPreflight(rootDir) {
|
|
|
6000
6171
|
issues.push(...next.issues);
|
|
6001
6172
|
warnings.push(...next.warnings);
|
|
6002
6173
|
}
|
|
6174
|
+
if (framework !== "vanilla") warnings.push(...checkBuildEnv(rootDir));
|
|
6003
6175
|
return { framework, issues, warnings };
|
|
6004
6176
|
}
|
|
6005
6177
|
|
|
6006
6178
|
// src/lib/backendDecl.ts
|
|
6007
|
-
var
|
|
6008
|
-
var
|
|
6179
|
+
var import_node_fs7 = require("fs");
|
|
6180
|
+
var import_node_path9 = require("path");
|
|
6009
6181
|
function readBackendDeclaration(dir = process.cwd()) {
|
|
6010
|
-
const path = (0,
|
|
6011
|
-
if (!(0,
|
|
6182
|
+
const path = (0, import_node_path9.join)(dir, ".agentful", "backend.json");
|
|
6183
|
+
if (!(0, import_node_fs7.existsSync)(path)) return null;
|
|
6012
6184
|
try {
|
|
6013
|
-
const parsed = JSON.parse((0,
|
|
6185
|
+
const parsed = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
|
|
6014
6186
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
6015
6187
|
const collections = Array.isArray(parsed.collections) ? parsed.collections.filter((c) => c && typeof c === "object" && !Array.isArray(c)) : [];
|
|
6016
6188
|
const secrets = Array.isArray(parsed.secrets) ? parsed.secrets.filter((s) => s && typeof s === "object" && !Array.isArray(s)) : [];
|
|
@@ -6054,19 +6226,19 @@ function describeBackendDeclaration(decl) {
|
|
|
6054
6226
|
function backendTabUrl(userId, projectId) {
|
|
6055
6227
|
return `${APP_URL}/workspace/${userId}/${projectId}?view=backend`;
|
|
6056
6228
|
}
|
|
6057
|
-
var ACTIONS_DIR = (0,
|
|
6229
|
+
var ACTIONS_DIR = (0, import_node_path9.join)(".server", "actions");
|
|
6058
6230
|
var ACTION_NAME = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
6059
6231
|
function checkBackendDeclaration(rootDir = process.cwd()) {
|
|
6060
6232
|
const issues = [];
|
|
6061
6233
|
const warnings = [];
|
|
6062
|
-
const actionsDir = (0,
|
|
6234
|
+
const actionsDir = (0, import_node_path9.join)(rootDir, ACTIONS_DIR);
|
|
6063
6235
|
const presentFiles = /* @__PURE__ */ new Set();
|
|
6064
|
-
if ((0,
|
|
6065
|
-
for (const entry of (0,
|
|
6066
|
-
const abs = (0,
|
|
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);
|
|
6067
6239
|
let isDir = false;
|
|
6068
6240
|
try {
|
|
6069
|
-
isDir = (0,
|
|
6241
|
+
isDir = (0, import_node_fs7.statSync)(abs).isDirectory();
|
|
6070
6242
|
} catch {
|
|
6071
6243
|
continue;
|
|
6072
6244
|
}
|
|
@@ -6118,6 +6290,7 @@ function checkBackendDeclaration(rootDir = process.cwd()) {
|
|
|
6118
6290
|
}
|
|
6119
6291
|
|
|
6120
6292
|
// src/lib/backendSync.ts
|
|
6293
|
+
var SWITCH_OFF_DELAY_S = contract_default.server_side.managed_actions.limits.switch_off_delay_s;
|
|
6121
6294
|
var joinMethods = (methods) => methods && methods.length ? methods.join(" + ") : "none";
|
|
6122
6295
|
function purposeOf(declaration, key) {
|
|
6123
6296
|
const entry = (declaration?.secrets ?? []).find((s) => s.key === key);
|
|
@@ -6260,9 +6433,9 @@ async function fetchBackendSessionState(auth, userId, projectId, opts = {}) {
|
|
|
6260
6433
|
}
|
|
6261
6434
|
function describeServerState(state) {
|
|
6262
6435
|
if (state.serverEnabled) {
|
|
6263
|
-
return
|
|
6436
|
+
return `Server: managed, enabled (Server Actions \u2014 functions we run for you). There is no activation point: pushed action code can change what the published app does immediately; warm instances may serve the previous code for up to five minutes. Switching it off in the Backend tab stops every action within ${SWITCH_OFF_DELAY_S} s.`;
|
|
6264
6437
|
}
|
|
6265
|
-
const notOn = "Action files you push are
|
|
6438
|
+
const notOn = "Action files you push are stored, but calls to them answer 404 server_not_enabled until you switch the managed server on in the Backend tab (`agentful backend` opens it \u2014 the CLI can enable the database, not the server). Switching on takes effect on the next call.";
|
|
6266
6439
|
if (state.serverMode === "byo") {
|
|
6267
6440
|
return `Server: your own API (${state.serverStatus || "not active"}) \u2014 /api/* on the app's domain is forwarded to it. Managed server: not switched on. ${notOn}`;
|
|
6268
6441
|
}
|
|
@@ -6282,8 +6455,8 @@ function describeBackendState(state) {
|
|
|
6282
6455
|
}
|
|
6283
6456
|
|
|
6284
6457
|
// src/lib/backendConsent.ts
|
|
6285
|
-
var
|
|
6286
|
-
var
|
|
6458
|
+
var import_node_fs8 = require("fs");
|
|
6459
|
+
var import_node_path10 = require("path");
|
|
6287
6460
|
var import_promises2 = require("readline/promises");
|
|
6288
6461
|
function declaresManagedDatabase(decl) {
|
|
6289
6462
|
if (!decl) return false;
|
|
@@ -6309,10 +6482,10 @@ function consentQuestion(decl) {
|
|
|
6309
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).'
|
|
6310
6483
|
].join("\n");
|
|
6311
6484
|
}
|
|
6312
|
-
var consentFile = () => (0,
|
|
6485
|
+
var consentFile = () => (0, import_node_path10.join)(configDir(), "backend-consent.json");
|
|
6313
6486
|
function readConsentFile() {
|
|
6314
6487
|
try {
|
|
6315
|
-
const raw = JSON.parse((0,
|
|
6488
|
+
const raw = JSON.parse((0, import_node_fs8.readFileSync)(consentFile(), "utf8"));
|
|
6316
6489
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
6317
6490
|
} catch {
|
|
6318
6491
|
return {};
|
|
@@ -6324,15 +6497,15 @@ function hasRememberedDecline(projectId) {
|
|
|
6324
6497
|
function rememberDecline(projectId) {
|
|
6325
6498
|
const all = readConsentFile();
|
|
6326
6499
|
all[projectId] = { declined_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6327
|
-
(0,
|
|
6328
|
-
(0,
|
|
6500
|
+
(0, import_node_fs8.mkdirSync)(configDir(), { recursive: true });
|
|
6501
|
+
(0, import_node_fs8.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
|
|
6329
6502
|
}
|
|
6330
6503
|
function forgetDecline(projectId) {
|
|
6331
|
-
if (!(0,
|
|
6504
|
+
if (!(0, import_node_fs8.existsSync)(consentFile())) return;
|
|
6332
6505
|
const all = readConsentFile();
|
|
6333
6506
|
if (!(projectId in all)) return;
|
|
6334
6507
|
delete all[projectId];
|
|
6335
|
-
(0,
|
|
6508
|
+
(0, import_node_fs8.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
|
|
6336
6509
|
}
|
|
6337
6510
|
async function enableManagedDatabase(auth, userId, projectId) {
|
|
6338
6511
|
try {
|
|
@@ -6540,13 +6713,14 @@ async function pushCommand(opts) {
|
|
|
6540
6713
|
ui.step("Building in the cloud (this can take a few minutes)\u2026");
|
|
6541
6714
|
const buildStartedAt = Date.now();
|
|
6542
6715
|
try {
|
|
6543
|
-
await request(`${PB_URL}/api/workspaces/${userId}/${projectId}/build`, {
|
|
6716
|
+
const built = await request(`${PB_URL}/api/workspaces/${userId}/${projectId}/build`, {
|
|
6544
6717
|
method: "POST",
|
|
6545
6718
|
token: auth.pb_token,
|
|
6546
6719
|
body: {},
|
|
6547
6720
|
timeoutMs: 66e4
|
|
6548
6721
|
});
|
|
6549
6722
|
ui.info("Build finished");
|
|
6723
|
+
for (const warning of built?.warnings ?? []) ui.warn(warning);
|
|
6550
6724
|
} catch (err2) {
|
|
6551
6725
|
if (err2 instanceof ApiError && err2.code === "network_error") {
|
|
6552
6726
|
ui.warn("Connection dropped during the build \u2014 polling for the result\u2026");
|
|
@@ -6709,15 +6883,15 @@ async function openCommand() {
|
|
|
6709
6883
|
// src/commands/tui.ts
|
|
6710
6884
|
var import_node_child_process6 = require("child_process");
|
|
6711
6885
|
var import_promises4 = require("readline/promises");
|
|
6712
|
-
var
|
|
6886
|
+
var import_node_path21 = require("path");
|
|
6713
6887
|
|
|
6714
6888
|
// src/lib/binWrapper.ts
|
|
6715
|
-
var
|
|
6716
|
-
var
|
|
6889
|
+
var import_node_fs9 = require("fs");
|
|
6890
|
+
var import_node_path11 = require("path");
|
|
6717
6891
|
var import_node_os3 = require("os");
|
|
6718
6892
|
function ensureCliOnPath() {
|
|
6719
|
-
const binDir = (0,
|
|
6720
|
-
(0,
|
|
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 });
|
|
6721
6895
|
const entry = process.argv[1];
|
|
6722
6896
|
if (!entry) return binDir;
|
|
6723
6897
|
const restore = (name) => {
|
|
@@ -6726,8 +6900,8 @@ function ensureCliOnPath() {
|
|
|
6726
6900
|
` : `export ${name}=${JSON.stringify(original)}
|
|
6727
6901
|
`;
|
|
6728
6902
|
};
|
|
6729
|
-
const wrapper = (0,
|
|
6730
|
-
(0,
|
|
6903
|
+
const wrapper = (0, import_node_path11.join)(binDir, "agentful");
|
|
6904
|
+
(0, import_node_fs9.writeFileSync)(
|
|
6731
6905
|
wrapper,
|
|
6732
6906
|
`#!/bin/sh
|
|
6733
6907
|
# Generated by the Agentful CLI so the coding agent can run \`agentful \u2026\`.
|
|
@@ -6737,7 +6911,7 @@ function ensureCliOnPath() {
|
|
|
6737
6911
|
"utf8"
|
|
6738
6912
|
);
|
|
6739
6913
|
try {
|
|
6740
|
-
(0,
|
|
6914
|
+
(0, import_node_fs9.chmodSync)(wrapper, 493);
|
|
6741
6915
|
} catch {
|
|
6742
6916
|
}
|
|
6743
6917
|
return binDir;
|
|
@@ -6747,9 +6921,9 @@ function ensureCliOnPath() {
|
|
|
6747
6921
|
init_branding();
|
|
6748
6922
|
|
|
6749
6923
|
// src/lib/engine.ts
|
|
6750
|
-
var
|
|
6924
|
+
var import_node_fs10 = require("fs");
|
|
6751
6925
|
var import_node_crypto = require("crypto");
|
|
6752
|
-
var
|
|
6926
|
+
var import_node_path12 = require("path");
|
|
6753
6927
|
var import_node_os4 = require("os");
|
|
6754
6928
|
var import_node_child_process3 = require("child_process");
|
|
6755
6929
|
var import_node_stream = require("stream");
|
|
@@ -6794,8 +6968,8 @@ function platformKey() {
|
|
|
6794
6968
|
);
|
|
6795
6969
|
}
|
|
6796
6970
|
function cacheDir(version) {
|
|
6797
|
-
const base = process.env.XDG_CACHE_HOME || (0,
|
|
6798
|
-
return (0,
|
|
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);
|
|
6799
6973
|
}
|
|
6800
6974
|
async function fetchManifest() {
|
|
6801
6975
|
try {
|
|
@@ -6806,7 +6980,7 @@ async function fetchManifest() {
|
|
|
6806
6980
|
}
|
|
6807
6981
|
async function sha256File(path) {
|
|
6808
6982
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
6809
|
-
await (0, import_promises3.pipeline)((0,
|
|
6983
|
+
await (0, import_promises3.pipeline)((0, import_node_fs10.createReadStream)(path), hash);
|
|
6810
6984
|
return hash.digest("hex");
|
|
6811
6985
|
}
|
|
6812
6986
|
async function ensureEngine() {
|
|
@@ -6815,12 +6989,12 @@ async function ensureEngine() {
|
|
|
6815
6989
|
noticeIfOutdated(manifest);
|
|
6816
6990
|
const version = manifest?.engine_version || FALLBACK_ENGINE_VERSION;
|
|
6817
6991
|
const dir = cacheDir(version);
|
|
6818
|
-
const binPath = (0,
|
|
6819
|
-
if ((0,
|
|
6992
|
+
const binPath = (0, import_node_path12.join)(dir, ENGINE_BINARY);
|
|
6993
|
+
if ((0, import_node_fs10.existsSync)(binPath)) return binPath;
|
|
6820
6994
|
const artifact = manifest?.artifacts?.[key];
|
|
6821
6995
|
const url = artifact?.url || `${APP_URL}/cli/engine/${version}/${key}${key.startsWith("darwin") ? ".zip" : ".tar.gz"}`;
|
|
6822
|
-
(0,
|
|
6823
|
-
const archivePath = (0,
|
|
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");
|
|
6824
6998
|
ui.step(`Preparing the ${brand.displayName} engine (first run only)\u2026`);
|
|
6825
6999
|
const resp = await fetch(url, {
|
|
6826
7000
|
redirect: "follow",
|
|
@@ -6834,11 +7008,11 @@ async function ensureEngine() {
|
|
|
6834
7008
|
`Could not download the engine (HTTP ${resp.status}). Check your connection and try again.`
|
|
6835
7009
|
);
|
|
6836
7010
|
}
|
|
6837
|
-
await (0, import_promises3.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0,
|
|
7011
|
+
await (0, import_promises3.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0, import_node_fs10.createWriteStream)(archivePath));
|
|
6838
7012
|
if (artifact?.sha256) {
|
|
6839
7013
|
const actual = await sha256File(archivePath);
|
|
6840
7014
|
if (actual !== artifact.sha256) {
|
|
6841
|
-
(0,
|
|
7015
|
+
(0, import_node_fs10.rmSync)(archivePath, { force: true });
|
|
6842
7016
|
throw new ApiError(
|
|
6843
7017
|
0,
|
|
6844
7018
|
"engine_checksum_mismatch",
|
|
@@ -6847,7 +7021,7 @@ async function ensureEngine() {
|
|
|
6847
7021
|
}
|
|
6848
7022
|
}
|
|
6849
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" });
|
|
6850
|
-
(0,
|
|
7024
|
+
(0, import_node_fs10.rmSync)(archivePath, { force: true });
|
|
6851
7025
|
if (extract.status !== 0) {
|
|
6852
7026
|
throw new ApiError(
|
|
6853
7027
|
0,
|
|
@@ -6855,24 +7029,24 @@ async function ensureEngine() {
|
|
|
6855
7029
|
`Could not unpack the engine (needs ${archivePath.endsWith(".zip") ? "unzip" : "tar"} on PATH).`
|
|
6856
7030
|
);
|
|
6857
7031
|
}
|
|
6858
|
-
const extracted = (0,
|
|
6859
|
-
if ((0,
|
|
6860
|
-
if (!(0,
|
|
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)) {
|
|
6861
7035
|
throw new ApiError(0, "engine_extract_failed", "Engine archive did not contain the expected binary.");
|
|
6862
7036
|
}
|
|
6863
|
-
(0,
|
|
7037
|
+
(0, import_node_fs10.chmodSync)(binPath, 493);
|
|
6864
7038
|
ui.ok(`Engine ready.`);
|
|
6865
7039
|
console.log(paint.dim(" powered by opencode (MIT) \xB7 run `agentful licenses` for details"));
|
|
6866
7040
|
return binPath;
|
|
6867
7041
|
}
|
|
6868
7042
|
|
|
6869
7043
|
// src/lib/gatewayToken.ts
|
|
6870
|
-
var
|
|
6871
|
-
var
|
|
6872
|
-
var cachePath = () => (0,
|
|
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");
|
|
6873
7047
|
async function ensureGatewaySession(auth, projectId) {
|
|
6874
7048
|
try {
|
|
6875
|
-
const cached = JSON.parse((0,
|
|
7049
|
+
const cached = JSON.parse((0, import_node_fs11.readFileSync)(cachePath(), "utf8"));
|
|
6876
7050
|
if (cached?.token && cached.expires_at - Date.now() / 1e3 > 3600) {
|
|
6877
7051
|
return cached;
|
|
6878
7052
|
}
|
|
@@ -6883,18 +7057,18 @@ async function ensureGatewaySession(auth, projectId) {
|
|
|
6883
7057
|
body: projectId ? { project_id: projectId } : {},
|
|
6884
7058
|
timeoutMs: 3e4
|
|
6885
7059
|
});
|
|
6886
|
-
(0,
|
|
6887
|
-
(0,
|
|
7060
|
+
(0, import_node_fs11.mkdirSync)(configDir(), { recursive: true });
|
|
7061
|
+
(0, import_node_fs11.writeFileSync)(cachePath(), JSON.stringify(res, null, 2) + "\n", "utf8");
|
|
6888
7062
|
try {
|
|
6889
|
-
(0,
|
|
7063
|
+
(0, import_node_fs11.chmodSync)(cachePath(), 384);
|
|
6890
7064
|
} catch {
|
|
6891
7065
|
}
|
|
6892
7066
|
return res;
|
|
6893
7067
|
}
|
|
6894
7068
|
|
|
6895
7069
|
// src/lib/engineConfig.ts
|
|
6896
|
-
var
|
|
6897
|
-
var
|
|
7070
|
+
var import_node_fs13 = require("fs");
|
|
7071
|
+
var import_node_path15 = require("path");
|
|
6898
7072
|
var import_node_os5 = require("os");
|
|
6899
7073
|
|
|
6900
7074
|
// src/branding/agentful-theme.json
|
|
@@ -7037,22 +7211,22 @@ ${cmd.template}
|
|
|
7037
7211
|
}
|
|
7038
7212
|
|
|
7039
7213
|
// src/lib/tools.ts
|
|
7040
|
-
var
|
|
7041
|
-
var
|
|
7214
|
+
var import_node_fs12 = require("fs");
|
|
7215
|
+
var import_node_path14 = require("path");
|
|
7042
7216
|
function assetsDir() {
|
|
7043
|
-
const here = (0,
|
|
7044
|
-
for (const candidate of [(0,
|
|
7045
|
-
if ((0,
|
|
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;
|
|
7046
7220
|
}
|
|
7047
7221
|
return null;
|
|
7048
7222
|
}
|
|
7049
7223
|
function installEngineTools(configDir2) {
|
|
7050
7224
|
const assets = assetsDir();
|
|
7051
7225
|
if (!assets) return false;
|
|
7052
|
-
const target = (0,
|
|
7053
|
-
(0,
|
|
7226
|
+
const target = (0, import_node_path14.join)(configDir2, "tools");
|
|
7227
|
+
(0, import_node_fs12.mkdirSync)(target, { recursive: true });
|
|
7054
7228
|
try {
|
|
7055
|
-
(0,
|
|
7229
|
+
(0, import_node_fs12.cpSync)((0, import_node_path14.join)(assets, "tools"), target, { recursive: true });
|
|
7056
7230
|
return true;
|
|
7057
7231
|
} catch {
|
|
7058
7232
|
return false;
|
|
@@ -7115,11 +7289,20 @@ function backendSessionLines(backend) {
|
|
|
7115
7289
|
return lines.join("\n");
|
|
7116
7290
|
}
|
|
7117
7291
|
function managedServerLine(backend) {
|
|
7292
|
+
const delay2 = contract_default.server_side.managed_actions.limits.switch_off_delay_s;
|
|
7118
7293
|
if (backend.serverEnabled) {
|
|
7119
|
-
return
|
|
7294
|
+
return `Managed server: **enabled**. **There is no activation point:** pushed action source can change what the published app does immediately, while warm instances may keep serving the previous code for up to five minutes. Switching the server off in the Backend tab stops every action within ${delay2} s.`;
|
|
7120
7295
|
}
|
|
7121
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. " : "";
|
|
7122
|
-
return `${ownApi}Managed server: **not switched on** in the Backend tab. **Action files you push are
|
|
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.`;
|
|
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");
|
|
7123
7306
|
}
|
|
7124
7307
|
var bytes = (n) => n >= 1024 * 1024 ? `${n / (1024 * 1024)} MB` : `${n / 1024} KB`;
|
|
7125
7308
|
function serverSideSection() {
|
|
@@ -7130,6 +7313,7 @@ function serverSideSection() {
|
|
|
7130
7313
|
`### ${heading} ${t.label}`,
|
|
7131
7314
|
"",
|
|
7132
7315
|
t.summary,
|
|
7316
|
+
...t.switch_note ? ["", t.switch_note] : [],
|
|
7133
7317
|
"",
|
|
7134
7318
|
"Offers:",
|
|
7135
7319
|
...t.offers.map((o) => `- ${o}`),
|
|
@@ -7147,7 +7331,7 @@ function serverSideSection() {
|
|
|
7147
7331
|
track(
|
|
7148
7332
|
"managed_actions",
|
|
7149
7333
|
"(a)",
|
|
7150
|
-
`${a.action_timeout_budget_s} s budget per action, ${a.hard_timeout_s} s hard limit, ${a.memory_mb} MB memory, request body \u2264 ${bytes(a.max_body_bytes)}, action source \u2264 ${bytes(a.max_code_bytes)}, ${a.project_concurrency} concurrent calls per project, self-call depth \u2264 ${a.max_action_depth}.`
|
|
7334
|
+
`${a.action_timeout_budget_s} s budget per action, ${a.hard_timeout_s} s hard limit, ${a.memory_mb} MB memory, request body \u2264 ${bytes(a.max_body_bytes)}, action source \u2264 ${bytes(a.max_code_bytes)}, ${a.project_concurrency} concurrent calls per project, self-call depth \u2264 ${a.max_action_depth}, switch-off delay \u2264 ${a.switch_off_delay_s} s.`
|
|
7151
7335
|
),
|
|
7152
7336
|
track("own_api", "(b)", null),
|
|
7153
7337
|
track(
|
|
@@ -7175,18 +7359,26 @@ is fine \u2014 but then say clearly that \`agentful push\` cannot deploy it.
|
|
|
7175
7359
|
Server-side logic has its own place \u2014 see "Where server logic belongs".
|
|
7176
7360
|
- The canonical build output is a root-level \`index.html\` inside the
|
|
7177
7361
|
framework's output directory.
|
|
7178
|
-
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
cloud \u2014 the CLI
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
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.
|
|
7190
7382
|
Never put a Supabase **secret / service-role key** in source: that one
|
|
7191
7383
|
belongs in Backend-tab secrets and is only readable from a Managed Server
|
|
7192
7384
|
Action.
|
|
@@ -7337,7 +7529,7 @@ var CLOUD_AGENT_PROMPT = `You are the Agentful Cloud build agent: everything you
|
|
|
7337
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.`;
|
|
7338
7530
|
function readAuthFile(path) {
|
|
7339
7531
|
try {
|
|
7340
|
-
return (0,
|
|
7532
|
+
return (0, import_node_fs13.readFileSync)(path, "utf8");
|
|
7341
7533
|
} catch {
|
|
7342
7534
|
return null;
|
|
7343
7535
|
}
|
|
@@ -7402,11 +7594,11 @@ function buildEngineConfig(opts) {
|
|
|
7402
7594
|
};
|
|
7403
7595
|
}
|
|
7404
7596
|
function engineXdg() {
|
|
7405
|
-
const root = (0,
|
|
7597
|
+
const root = (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful");
|
|
7406
7598
|
return {
|
|
7407
|
-
configHome: (0,
|
|
7408
|
-
dataHome: (0,
|
|
7409
|
-
stateHome: (0,
|
|
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")
|
|
7410
7602
|
};
|
|
7411
7603
|
}
|
|
7412
7604
|
async function resolveTheme() {
|
|
@@ -7425,24 +7617,24 @@ async function resolveTheme() {
|
|
|
7425
7617
|
}
|
|
7426
7618
|
async function writeEngineSession(session, catalog, localProviders = {}, framework = "unknown", skillsInstruction = null, backendState, model) {
|
|
7427
7619
|
const xdg = engineXdg();
|
|
7428
|
-
const configDir2 = (0,
|
|
7429
|
-
const dataDir = (0,
|
|
7430
|
-
const themesDir = (0,
|
|
7431
|
-
const pluginsDir = (0,
|
|
7432
|
-
const commandsDir = (0,
|
|
7433
|
-
for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0,
|
|
7434
|
-
(0,
|
|
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 });
|
|
7435
7627
|
}
|
|
7436
7628
|
const imagegenAvailable = installEngineTools(configDir2) && session.img_on !== false;
|
|
7437
|
-
const cloudInstructionsPath = (0,
|
|
7438
|
-
(0,
|
|
7439
|
-
const skillsPath = (0,
|
|
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");
|
|
7440
7632
|
const instructionPaths = [cloudInstructionsPath];
|
|
7441
7633
|
if (skillsInstruction) {
|
|
7442
|
-
(0,
|
|
7634
|
+
(0, import_node_fs13.writeFileSync)(skillsPath, skillsInstruction);
|
|
7443
7635
|
instructionPaths.push(skillsPath);
|
|
7444
7636
|
} else {
|
|
7445
|
-
(0,
|
|
7637
|
+
(0, import_node_fs13.rmSync)(skillsPath, { force: true });
|
|
7446
7638
|
}
|
|
7447
7639
|
const config = buildEngineConfig({
|
|
7448
7640
|
session,
|
|
@@ -7452,13 +7644,13 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
7452
7644
|
instructionPaths,
|
|
7453
7645
|
model
|
|
7454
7646
|
});
|
|
7455
|
-
(0,
|
|
7456
|
-
const authPath2 = (0,
|
|
7457
|
-
(0,
|
|
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));
|
|
7458
7650
|
const { brandingPluginSource: brandingPluginSource2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
|
|
7459
|
-
const pluginPath = (0,
|
|
7460
|
-
(0,
|
|
7461
|
-
(0,
|
|
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({
|
|
7462
7654
|
theme: "agentful",
|
|
7463
7655
|
plugin: [`file://${pluginPath}`],
|
|
7464
7656
|
// The engine's own sidebar sections are plugins with fixed ids, and
|
|
@@ -7470,13 +7662,13 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
7470
7662
|
// state over this map.
|
|
7471
7663
|
plugin_enabled: DISABLED_ENGINE_PLUGINS
|
|
7472
7664
|
}, null, 2));
|
|
7473
|
-
(0,
|
|
7665
|
+
(0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(themesDir, "agentful.json"), JSON.stringify(await resolveTheme(), null, 2));
|
|
7474
7666
|
for (const name of Object.keys(SLASH_COMMANDS)) {
|
|
7475
|
-
(0,
|
|
7667
|
+
(0, import_node_fs13.writeFileSync)((0, import_node_path15.join)(commandsDir, `${name}.md`), commandMarkdown(name));
|
|
7476
7668
|
}
|
|
7477
7669
|
for (const legacy of ["xdg-config", "xdg-data", "xdg-state"]) {
|
|
7478
7670
|
try {
|
|
7479
|
-
(0,
|
|
7671
|
+
(0, import_node_fs13.rmSync)((0, import_node_path15.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful", legacy), { recursive: true, force: true });
|
|
7480
7672
|
} catch {
|
|
7481
7673
|
}
|
|
7482
7674
|
}
|
|
@@ -7484,8 +7676,8 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
7484
7676
|
}
|
|
7485
7677
|
|
|
7486
7678
|
// src/lib/skills.ts
|
|
7487
|
-
var
|
|
7488
|
-
var
|
|
7679
|
+
var import_node_fs14 = require("fs");
|
|
7680
|
+
var import_node_path16 = require("path");
|
|
7489
7681
|
|
|
7490
7682
|
// src/generated/skills.json
|
|
7491
7683
|
var skills_default = {
|
|
@@ -7554,7 +7746,7 @@ var SCAFFOLD_BY_FRAMEWORK = {
|
|
|
7554
7746
|
};
|
|
7555
7747
|
function hasVueDependency(rootDir) {
|
|
7556
7748
|
try {
|
|
7557
|
-
const pkg = JSON.parse((0,
|
|
7749
|
+
const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path16.join)(rootDir, "package.json"), "utf8"));
|
|
7558
7750
|
return Boolean({ ...pkg.dependencies, ...pkg.devDependencies }["vue"]);
|
|
7559
7751
|
} catch {
|
|
7560
7752
|
return false;
|
|
@@ -7584,7 +7776,7 @@ function renderSkillsInstruction(names) {
|
|
|
7584
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";
|
|
7585
7777
|
}
|
|
7586
7778
|
function skillsInstructionFor(framework, rootDir) {
|
|
7587
|
-
if (!(0,
|
|
7779
|
+
if (!(0, import_node_fs14.existsSync)(rootDir)) return null;
|
|
7588
7780
|
return renderSkillsInstruction(selectSkills(framework, rootDir));
|
|
7589
7781
|
}
|
|
7590
7782
|
|
|
@@ -7732,15 +7924,15 @@ function decideLocalProviders(policy) {
|
|
|
7732
7924
|
}
|
|
7733
7925
|
|
|
7734
7926
|
// src/lib/localProviders.ts
|
|
7735
|
-
var
|
|
7736
|
-
var
|
|
7927
|
+
var import_node_fs15 = require("fs");
|
|
7928
|
+
var import_node_path17 = require("path");
|
|
7737
7929
|
var LOCAL_PROVIDERS_FILE = "local-providers.json";
|
|
7738
7930
|
function localProvidersPath() {
|
|
7739
|
-
return (0,
|
|
7931
|
+
return (0, import_node_path17.join)(configDir(), LOCAL_PROVIDERS_FILE);
|
|
7740
7932
|
}
|
|
7741
7933
|
function readLocalProviders() {
|
|
7742
7934
|
try {
|
|
7743
|
-
const raw = JSON.parse((0,
|
|
7935
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(localProvidersPath(), "utf8"));
|
|
7744
7936
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
7745
7937
|
const map = raw.providers && typeof raw.providers === "object" ? raw.providers : raw;
|
|
7746
7938
|
const usable = {};
|
|
@@ -7775,8 +7967,8 @@ function resolveLocalProviders(policy) {
|
|
|
7775
7967
|
}
|
|
7776
7968
|
function writeLocalProvidersExample() {
|
|
7777
7969
|
const path = localProvidersPath();
|
|
7778
|
-
if ((0,
|
|
7779
|
-
(0,
|
|
7970
|
+
if ((0, import_node_fs15.existsSync)(path)) return path;
|
|
7971
|
+
(0, import_node_fs15.mkdirSync)(configDir(), { recursive: true });
|
|
7780
7972
|
const example = {
|
|
7781
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.',
|
|
7782
7974
|
_anthropic: {
|
|
@@ -7786,17 +7978,17 @@ function writeLocalProvidersExample() {
|
|
|
7786
7978
|
models: { "claude-sonnet-4-5": { name: "Claude Sonnet 4.5 (my key)" } }
|
|
7787
7979
|
}
|
|
7788
7980
|
};
|
|
7789
|
-
(0,
|
|
7981
|
+
(0, import_node_fs15.writeFileSync)(path, JSON.stringify(example, null, 2) + "\n", "utf8");
|
|
7790
7982
|
try {
|
|
7791
|
-
(0,
|
|
7983
|
+
(0, import_node_fs15.chmodSync)(path, 384);
|
|
7792
7984
|
} catch {
|
|
7793
7985
|
}
|
|
7794
7986
|
return path;
|
|
7795
7987
|
}
|
|
7796
7988
|
|
|
7797
7989
|
// src/lib/sessions.ts
|
|
7798
|
-
var
|
|
7799
|
-
var
|
|
7990
|
+
var import_node_fs16 = require("fs");
|
|
7991
|
+
var import_node_path18 = require("path");
|
|
7800
7992
|
var import_node_child_process4 = require("child_process");
|
|
7801
7993
|
function parseSessionModel(raw) {
|
|
7802
7994
|
if (!raw) return null;
|
|
@@ -7813,8 +8005,8 @@ function parseSessionModel(raw) {
|
|
|
7813
8005
|
}
|
|
7814
8006
|
}
|
|
7815
8007
|
function modelForSession(sessionID) {
|
|
7816
|
-
const dbPath = (0,
|
|
7817
|
-
if (!(0,
|
|
8008
|
+
const dbPath = (0, import_node_path18.join)(engineXdg().dataHome, "opencode", "opencode.db");
|
|
8009
|
+
if (!(0, import_node_fs16.existsSync)(dbPath)) return null;
|
|
7818
8010
|
const escaped = sessionID.replace(/'/g, "''");
|
|
7819
8011
|
const res = (0, import_node_child_process4.spawnSync)(
|
|
7820
8012
|
"sqlite3",
|
|
@@ -7835,8 +8027,8 @@ function modelForSession(sessionID) {
|
|
|
7835
8027
|
}
|
|
7836
8028
|
}
|
|
7837
8029
|
function lastSessionForDirectory(cwd = process.cwd()) {
|
|
7838
|
-
const dbPath = (0,
|
|
7839
|
-
if (!(0,
|
|
8030
|
+
const dbPath = (0, import_node_path18.join)(engineXdg().dataHome, "opencode", "opencode.db");
|
|
8031
|
+
if (!(0, import_node_fs16.existsSync)(dbPath)) return null;
|
|
7840
8032
|
const escaped = cwd.replace(/'/g, "''");
|
|
7841
8033
|
const res = (0, import_node_child_process4.spawnSync)(
|
|
7842
8034
|
"sqlite3",
|
|
@@ -7862,9 +8054,9 @@ function lastSessionForDirectory(cwd = process.cwd()) {
|
|
|
7862
8054
|
}
|
|
7863
8055
|
|
|
7864
8056
|
// src/lib/modelPin.ts
|
|
7865
|
-
var
|
|
7866
|
-
var
|
|
7867
|
-
var PROJECT_MODEL_PIN = (0,
|
|
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");
|
|
7868
8060
|
function isCanonicalModel(value) {
|
|
7869
8061
|
const slash = value.indexOf("/");
|
|
7870
8062
|
return slash > 0 && slash < value.length - 1 && !/\s/.test(value);
|
|
@@ -7884,10 +8076,10 @@ function assertModelPin(pin, source) {
|
|
|
7884
8076
|
return pin;
|
|
7885
8077
|
}
|
|
7886
8078
|
function readProjectModelPin(cwd = process.cwd()) {
|
|
7887
|
-
const path = (0,
|
|
8079
|
+
const path = (0, import_node_path19.join)(cwd, PROJECT_MODEL_PIN);
|
|
7888
8080
|
let raw;
|
|
7889
8081
|
try {
|
|
7890
|
-
raw = (0,
|
|
8082
|
+
raw = (0, import_node_fs17.readFileSync)(path, "utf8");
|
|
7891
8083
|
} catch (error) {
|
|
7892
8084
|
const code = error.code;
|
|
7893
8085
|
if (code === "ENOENT") return null;
|
|
@@ -7914,7 +8106,7 @@ function readProjectModelPin(cwd = process.cwd()) {
|
|
|
7914
8106
|
function readEngineVariants(xdg) {
|
|
7915
8107
|
try {
|
|
7916
8108
|
const parsed = JSON.parse(
|
|
7917
|
-
(0,
|
|
8109
|
+
(0, import_node_fs17.readFileSync)((0, import_node_path19.join)(xdg.stateHome, "opencode", "model.json"), "utf8")
|
|
7918
8110
|
);
|
|
7919
8111
|
if (!parsed.variant || typeof parsed.variant !== "object" || Array.isArray(parsed.variant)) return {};
|
|
7920
8112
|
return Object.fromEntries(
|
|
@@ -7926,17 +8118,17 @@ function readEngineVariants(xdg) {
|
|
|
7926
8118
|
}
|
|
7927
8119
|
function writeEngineVariant(xdg, model, variant) {
|
|
7928
8120
|
assertModelPin({ model, variant }, "Selected");
|
|
7929
|
-
const path = (0,
|
|
8121
|
+
const path = (0, import_node_path19.join)(xdg.stateHome, "opencode", "model.json");
|
|
7930
8122
|
let state = {};
|
|
7931
8123
|
try {
|
|
7932
|
-
const parsed = JSON.parse((0,
|
|
8124
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
|
|
7933
8125
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) state = parsed;
|
|
7934
8126
|
} catch {
|
|
7935
8127
|
}
|
|
7936
8128
|
const existing = state.variant;
|
|
7937
8129
|
const variants = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
|
|
7938
8130
|
state.variant = { ...variants, [model]: variant };
|
|
7939
|
-
(0,
|
|
8131
|
+
(0, import_node_fs17.writeFileSync)(path, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
7940
8132
|
}
|
|
7941
8133
|
function resolveModelPin(opts) {
|
|
7942
8134
|
const cliPin = opts.cliModel ? assertModelPin({ model: opts.cliModel, variant: opts.cliVariant }, "CLI") : null;
|
|
@@ -7985,8 +8177,8 @@ function resolveModelPin(opts) {
|
|
|
7985
8177
|
// src/lib/engineModels.ts
|
|
7986
8178
|
var import_node_child_process5 = require("child_process");
|
|
7987
8179
|
var import_node_util = require("util");
|
|
7988
|
-
var
|
|
7989
|
-
var
|
|
8180
|
+
var import_node_fs18 = require("fs");
|
|
8181
|
+
var import_node_path20 = require("path");
|
|
7990
8182
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process5.execFile);
|
|
7991
8183
|
function parseEngineModelsOutput(output) {
|
|
7992
8184
|
return Array.from(new Set(
|
|
@@ -8037,7 +8229,7 @@ async function assertEngineModelAvailable(binPath, xdg, model, listModels = list
|
|
|
8037
8229
|
function readConnectedEngineProviders(xdg) {
|
|
8038
8230
|
try {
|
|
8039
8231
|
const parsed = JSON.parse(
|
|
8040
|
-
(0,
|
|
8232
|
+
(0, import_node_fs18.readFileSync)((0, import_node_path20.join)(xdg.dataHome, "opencode", "auth.json"), "utf8")
|
|
8041
8233
|
);
|
|
8042
8234
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
|
|
8043
8235
|
return Object.keys(parsed).filter((id) => id !== "agentful").sort();
|
|
@@ -8465,7 +8657,7 @@ async function tuiCommand(opts = {}) {
|
|
|
8465
8657
|
...process.env,
|
|
8466
8658
|
// Slash commands run `agentful …` through the agent's bash tool, which
|
|
8467
8659
|
// has no access to the user's shell aliases.
|
|
8468
|
-
PATH: `${binDir}${
|
|
8660
|
+
PATH: `${binDir}${import_node_path21.delimiter}${process.env.PATH || ""}`,
|
|
8469
8661
|
XDG_CONFIG_HOME: xdg.configHome,
|
|
8470
8662
|
XDG_DATA_HOME: xdg.dataHome,
|
|
8471
8663
|
XDG_STATE_HOME: xdg.stateHome,
|
|
@@ -8596,38 +8788,38 @@ async function shareCommand(opts) {
|
|
|
8596
8788
|
}
|
|
8597
8789
|
|
|
8598
8790
|
// src/commands/pull.ts
|
|
8599
|
-
var
|
|
8600
|
-
var
|
|
8791
|
+
var import_node_fs20 = require("fs");
|
|
8792
|
+
var import_node_path23 = require("path");
|
|
8601
8793
|
init_branding();
|
|
8602
8794
|
init_branding();
|
|
8603
8795
|
|
|
8604
8796
|
// src/lib/pullFiles.ts
|
|
8605
|
-
var
|
|
8606
|
-
var
|
|
8797
|
+
var import_node_fs19 = require("fs");
|
|
8798
|
+
var import_node_path22 = require("path");
|
|
8607
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;
|
|
8608
8800
|
function inlineContent(value) {
|
|
8609
8801
|
return typeof value === "object" && value !== null && "content" in value ? String(value.content) : String(value ?? "");
|
|
8610
8802
|
}
|
|
8611
8803
|
function writePulledWorkspaceEntry(root, rel, value) {
|
|
8612
|
-
const target = (0,
|
|
8613
|
-
(0,
|
|
8804
|
+
const target = (0, import_node_path22.join)(root, rel);
|
|
8805
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path22.dirname)(target), { recursive: true });
|
|
8614
8806
|
const content = inlineContent(value);
|
|
8615
8807
|
if (INLINE_BASE64_EXTENSIONS.test(rel)) {
|
|
8616
|
-
(0,
|
|
8808
|
+
(0, import_node_fs19.writeFileSync)(target, Buffer.from(content, "base64"));
|
|
8617
8809
|
return;
|
|
8618
8810
|
}
|
|
8619
|
-
(0,
|
|
8811
|
+
(0, import_node_fs19.writeFileSync)(target, content, "utf8");
|
|
8620
8812
|
}
|
|
8621
8813
|
function writePulledBackendDeclaration(root, declaration) {
|
|
8622
|
-
const target = (0,
|
|
8623
|
-
(0,
|
|
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 });
|
|
8624
8816
|
const {
|
|
8625
8817
|
source: _source,
|
|
8626
8818
|
received_at: _receivedAt,
|
|
8627
8819
|
last_sync: _lastSync,
|
|
8628
8820
|
...portableDeclaration
|
|
8629
8821
|
} = declaration;
|
|
8630
|
-
(0,
|
|
8822
|
+
(0, import_node_fs19.writeFileSync)(target, `${JSON.stringify(portableDeclaration, null, 2)}
|
|
8631
8823
|
`, "utf8");
|
|
8632
8824
|
}
|
|
8633
8825
|
|
|
@@ -8636,7 +8828,7 @@ async function pullCommand(opts) {
|
|
|
8636
8828
|
console.log(banner());
|
|
8637
8829
|
const auth = await ensureAuth();
|
|
8638
8830
|
const project = requireProject();
|
|
8639
|
-
const nonHidden = (0,
|
|
8831
|
+
const nonHidden = (0, import_node_fs20.readdirSync)(process.cwd()).filter((n) => n !== ".agentful" && !n.startsWith("."));
|
|
8640
8832
|
if (nonHidden.length > 0 && !opts.force) {
|
|
8641
8833
|
throw new ApiError(
|
|
8642
8834
|
0,
|
|
@@ -8663,9 +8855,9 @@ async function pullCommand(opts) {
|
|
|
8663
8855
|
ui.warn(`Skipped ${rel} (HTTP ${resp.status})`);
|
|
8664
8856
|
continue;
|
|
8665
8857
|
}
|
|
8666
|
-
const target = (0,
|
|
8667
|
-
(0,
|
|
8668
|
-
(0,
|
|
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()));
|
|
8669
8861
|
written++;
|
|
8670
8862
|
}
|
|
8671
8863
|
} else if (data.files) {
|