agentful 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +244 -99
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3044,7 +3044,7 @@ var VERSION, brand, useColor, wrap, paint, sym, ui;
|
|
|
3044
3044
|
var init_branding = __esm({
|
|
3045
3045
|
"src/branding.ts"() {
|
|
3046
3046
|
"use strict";
|
|
3047
|
-
VERSION = "0.3.
|
|
3047
|
+
VERSION = "0.3.1" ? "0.3.1" : null.version;
|
|
3048
3048
|
brand = {
|
|
3049
3049
|
name: "agentful",
|
|
3050
3050
|
// the command users type
|
|
@@ -5873,6 +5873,135 @@ function describeBackendState(state) {
|
|
|
5873
5873
|
return out;
|
|
5874
5874
|
}
|
|
5875
5875
|
|
|
5876
|
+
// src/lib/backendConsent.ts
|
|
5877
|
+
var import_node_fs7 = require("fs");
|
|
5878
|
+
var import_node_path9 = require("path");
|
|
5879
|
+
var import_promises2 = require("readline/promises");
|
|
5880
|
+
function declaresManagedDatabase(decl) {
|
|
5881
|
+
if (!decl) return false;
|
|
5882
|
+
return Boolean(decl.managed_db) || (decl.collections?.length ?? 0) > 0 || authMethodsOf(decl).length > 0;
|
|
5883
|
+
}
|
|
5884
|
+
function decideConsent(input) {
|
|
5885
|
+
if (!declaresManagedDatabase(input.declaration)) return { kind: "not_applicable" };
|
|
5886
|
+
if (input.state === null) return { kind: "state_unknown" };
|
|
5887
|
+
if (input.state.databaseEnabled) return { kind: "already_enabled" };
|
|
5888
|
+
if (input.yes) return { kind: "enable", via: "flag" };
|
|
5889
|
+
if (input.rememberedDecline) return { kind: "skip", reason: "remembered_decline" };
|
|
5890
|
+
if (!input.interactive) return { kind: "skip", reason: "non_interactive" };
|
|
5891
|
+
return { kind: "ask" };
|
|
5892
|
+
}
|
|
5893
|
+
function consentQuestion(decl) {
|
|
5894
|
+
const names = (decl.collections ?? []).map((c) => c.name).filter(Boolean);
|
|
5895
|
+
const what = names.length ? `a managed database with ${names.length} collection(s): ${names.slice(0, 6).join(", ")}${names.length > 6 ? ", \u2026" : ""}` : "a managed database";
|
|
5896
|
+
return [
|
|
5897
|
+
`This project declares ${what}.`,
|
|
5898
|
+
"Enable it on the platform now? Two things change:",
|
|
5899
|
+
" \u2022 /api/* on your preview domain is routed to the backend \u2014 a static file under /api/ would no longer be served",
|
|
5900
|
+
" \u2022 the data API goes live under the declared access rules (a `public` collection is readable AND writable without login)",
|
|
5901
|
+
'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).'
|
|
5902
|
+
].join("\n");
|
|
5903
|
+
}
|
|
5904
|
+
var consentFile = () => (0, import_node_path9.join)(configDir(), "backend-consent.json");
|
|
5905
|
+
function readConsentFile() {
|
|
5906
|
+
try {
|
|
5907
|
+
const raw = JSON.parse((0, import_node_fs7.readFileSync)(consentFile(), "utf8"));
|
|
5908
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
5909
|
+
} catch {
|
|
5910
|
+
return {};
|
|
5911
|
+
}
|
|
5912
|
+
}
|
|
5913
|
+
function hasRememberedDecline(projectId) {
|
|
5914
|
+
return Boolean(readConsentFile()[projectId]);
|
|
5915
|
+
}
|
|
5916
|
+
function rememberDecline(projectId) {
|
|
5917
|
+
const all = readConsentFile();
|
|
5918
|
+
all[projectId] = { declined_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
5919
|
+
(0, import_node_fs7.mkdirSync)(configDir(), { recursive: true });
|
|
5920
|
+
(0, import_node_fs7.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
|
|
5921
|
+
}
|
|
5922
|
+
function forgetDecline(projectId) {
|
|
5923
|
+
if (!(0, import_node_fs7.existsSync)(consentFile())) return;
|
|
5924
|
+
const all = readConsentFile();
|
|
5925
|
+
if (!(projectId in all)) return;
|
|
5926
|
+
delete all[projectId];
|
|
5927
|
+
(0, import_node_fs7.writeFileSync)(consentFile(), JSON.stringify(all, null, 2) + "\n", "utf8");
|
|
5928
|
+
}
|
|
5929
|
+
async function enableManagedDatabase(auth, userId, projectId) {
|
|
5930
|
+
try {
|
|
5931
|
+
const body = await request(`${API_URL}/api/projects/${userId}/${projectId}/backend/database`, {
|
|
5932
|
+
method: "PUT",
|
|
5933
|
+
token: auth.pb_token,
|
|
5934
|
+
timeoutMs: 6e4,
|
|
5935
|
+
body: { mode: "managed", provider: "managed_document" }
|
|
5936
|
+
});
|
|
5937
|
+
const status = String(body?.data?.status ?? body?.status ?? "");
|
|
5938
|
+
return status === "active" ? { ok: true, status } : { ok: false, status, message: body?.error?.message || body?.message };
|
|
5939
|
+
} catch (err2) {
|
|
5940
|
+
return { ok: false, message: err2?.message || String(err2) };
|
|
5941
|
+
}
|
|
5942
|
+
}
|
|
5943
|
+
async function ensureDatabaseConsent(opts) {
|
|
5944
|
+
const lines = [];
|
|
5945
|
+
if (!declaresManagedDatabase(opts.declaration)) {
|
|
5946
|
+
return { decision: { kind: "not_applicable" }, enabled: false, lines };
|
|
5947
|
+
}
|
|
5948
|
+
const state = await fetchBackendSessionState(opts.auth, opts.userId, opts.projectId);
|
|
5949
|
+
const interactive = opts.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
5950
|
+
let decision = decideConsent({
|
|
5951
|
+
declaration: opts.declaration,
|
|
5952
|
+
state,
|
|
5953
|
+
yes: opts.yes,
|
|
5954
|
+
interactive,
|
|
5955
|
+
rememberedDecline: hasRememberedDecline(opts.projectId)
|
|
5956
|
+
});
|
|
5957
|
+
if (decision.kind === "ask") {
|
|
5958
|
+
const ask = opts.ask ?? (async (q) => {
|
|
5959
|
+
const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
|
|
5960
|
+
try {
|
|
5961
|
+
return await rl.question(`${q}
|
|
5962
|
+
Enable the managed database? [y/N] `);
|
|
5963
|
+
} finally {
|
|
5964
|
+
rl.close();
|
|
5965
|
+
}
|
|
5966
|
+
});
|
|
5967
|
+
const answer = (await ask(consentQuestion(opts.declaration))).trim().toLowerCase();
|
|
5968
|
+
if (answer === "y" || answer === "yes") {
|
|
5969
|
+
decision = { kind: "enable", via: "answer" };
|
|
5970
|
+
} else {
|
|
5971
|
+
rememberDecline(opts.projectId);
|
|
5972
|
+
decision = { kind: "skip", reason: "declined" };
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
switch (decision.kind) {
|
|
5976
|
+
case "state_unknown":
|
|
5977
|
+
lines.push({ kind: "warn", text: "Could not read the backend state \u2014 the database is NOT enabled by this push; the declaration is stored and reported." });
|
|
5978
|
+
return { decision, enabled: false, lines };
|
|
5979
|
+
case "already_enabled":
|
|
5980
|
+
return { decision, enabled: true, lines };
|
|
5981
|
+
case "skip":
|
|
5982
|
+
if (decision.reason === "non_interactive") {
|
|
5983
|
+
lines.push({ kind: "info", text: "Managed database declared but not enabled \u2014 non-interactive push never enables it. Use `agentful push --yes` (CI) or enable it in the Backend tab (`agentful backend`)." });
|
|
5984
|
+
} else if (decision.reason === "remembered_decline") {
|
|
5985
|
+
lines.push({ kind: "info", text: "Managed database declared but not enabled \u2014 you declined earlier for this project. `agentful push --yes` or `agentful backend` enables it." });
|
|
5986
|
+
} else {
|
|
5987
|
+
lines.push({ kind: "info", text: "Not enabled. The declaration is stored; `agentful push --yes` or the Backend tab enables the database later." });
|
|
5988
|
+
}
|
|
5989
|
+
return { decision, enabled: false, lines };
|
|
5990
|
+
case "enable": {
|
|
5991
|
+
const result = await enableManagedDatabase(opts.auth, opts.userId, opts.projectId);
|
|
5992
|
+
if (result.ok) {
|
|
5993
|
+
forgetDecline(opts.projectId);
|
|
5994
|
+
lines.push({ kind: "ok", text: `Managed database enabled${decision.via === "flag" ? " (--yes)" : ""} \u2014 this push applies the declaration.` });
|
|
5995
|
+
return { decision, enabled: true, lines };
|
|
5996
|
+
}
|
|
5997
|
+
lines.push({ kind: "warn", text: `Could not enable the managed database${result.message ? `: ${result.message}` : ""}. The push continues; enable it in the Backend tab (\`agentful backend\`).` });
|
|
5998
|
+
return { decision, enabled: false, lines };
|
|
5999
|
+
}
|
|
6000
|
+
default:
|
|
6001
|
+
return { decision, enabled: false, lines };
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
|
|
5876
6005
|
// src/lib/buildStatus.ts
|
|
5877
6006
|
init_branding();
|
|
5878
6007
|
var DIAGNOSIS_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
@@ -5962,8 +6091,22 @@ async function pushCommand(opts) {
|
|
|
5962
6091
|
`Packed ${(zip.bytes / 1024 / 1024).toFixed(1)} MB compressed \u2014 the platform caps uploads at ${Math.floor(MAX_ZIP_UPLOAD_BYTES / (1024 * 1024))} MB. Remove large media or generated files from the source tree (node_modules, dist and .git are excluded automatically); large assets belong in the platform asset flow.`
|
|
5963
6092
|
);
|
|
5964
6093
|
}
|
|
5965
|
-
ui.step("Uploading to your workspace\u2026");
|
|
5966
6094
|
const declaration = mode === "source" ? readBackendDeclaration() : null;
|
|
6095
|
+
if (declaration) {
|
|
6096
|
+
const consent = await ensureDatabaseConsent({
|
|
6097
|
+
auth,
|
|
6098
|
+
userId,
|
|
6099
|
+
projectId,
|
|
6100
|
+
declaration,
|
|
6101
|
+
yes: opts.yes
|
|
6102
|
+
});
|
|
6103
|
+
for (const line of consent.lines) {
|
|
6104
|
+
if (line.kind === "ok") ui.ok(line.text);
|
|
6105
|
+
else if (line.kind === "warn") ui.warn(line.text);
|
|
6106
|
+
else ui.info(line.text);
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6109
|
+
ui.step("Uploading to your workspace\u2026");
|
|
5967
6110
|
const upload = await request(
|
|
5968
6111
|
`${API_URL}/api/workspaces/${userId}/${projectId}/source-zip`,
|
|
5969
6112
|
{
|
|
@@ -6150,15 +6293,15 @@ async function openCommand() {
|
|
|
6150
6293
|
|
|
6151
6294
|
// src/commands/tui.ts
|
|
6152
6295
|
var import_node_child_process5 = require("child_process");
|
|
6153
|
-
var
|
|
6296
|
+
var import_node_path18 = require("path");
|
|
6154
6297
|
|
|
6155
6298
|
// src/lib/binWrapper.ts
|
|
6156
|
-
var
|
|
6157
|
-
var
|
|
6299
|
+
var import_node_fs8 = require("fs");
|
|
6300
|
+
var import_node_path10 = require("path");
|
|
6158
6301
|
var import_node_os3 = require("os");
|
|
6159
6302
|
function ensureCliOnPath() {
|
|
6160
|
-
const binDir = (0,
|
|
6161
|
-
(0,
|
|
6303
|
+
const binDir = (0, import_node_path10.join)((0, import_node_os3.homedir)(), ".local", "share", "agentful", "bin");
|
|
6304
|
+
(0, import_node_fs8.mkdirSync)(binDir, { recursive: true });
|
|
6162
6305
|
const entry = process.argv[1];
|
|
6163
6306
|
if (!entry) return binDir;
|
|
6164
6307
|
const restore = (name) => {
|
|
@@ -6167,8 +6310,8 @@ function ensureCliOnPath() {
|
|
|
6167
6310
|
` : `export ${name}=${JSON.stringify(original)}
|
|
6168
6311
|
`;
|
|
6169
6312
|
};
|
|
6170
|
-
const wrapper = (0,
|
|
6171
|
-
(0,
|
|
6313
|
+
const wrapper = (0, import_node_path10.join)(binDir, "agentful");
|
|
6314
|
+
(0, import_node_fs8.writeFileSync)(
|
|
6172
6315
|
wrapper,
|
|
6173
6316
|
`#!/bin/sh
|
|
6174
6317
|
# Generated by the Agentful CLI so the coding agent can run \`agentful \u2026\`.
|
|
@@ -6178,7 +6321,7 @@ function ensureCliOnPath() {
|
|
|
6178
6321
|
"utf8"
|
|
6179
6322
|
);
|
|
6180
6323
|
try {
|
|
6181
|
-
(0,
|
|
6324
|
+
(0, import_node_fs8.chmodSync)(wrapper, 493);
|
|
6182
6325
|
} catch {
|
|
6183
6326
|
}
|
|
6184
6327
|
return binDir;
|
|
@@ -6188,13 +6331,13 @@ function ensureCliOnPath() {
|
|
|
6188
6331
|
init_branding();
|
|
6189
6332
|
|
|
6190
6333
|
// src/lib/engine.ts
|
|
6191
|
-
var
|
|
6334
|
+
var import_node_fs9 = require("fs");
|
|
6192
6335
|
var import_node_crypto = require("crypto");
|
|
6193
|
-
var
|
|
6336
|
+
var import_node_path11 = require("path");
|
|
6194
6337
|
var import_node_os4 = require("os");
|
|
6195
6338
|
var import_node_child_process3 = require("child_process");
|
|
6196
6339
|
var import_node_stream = require("stream");
|
|
6197
|
-
var
|
|
6340
|
+
var import_promises3 = require("stream/promises");
|
|
6198
6341
|
init_branding();
|
|
6199
6342
|
var ENGINE_BINARY = "agentful-engine";
|
|
6200
6343
|
var FALLBACK_ENGINE_VERSION = "v1.18.18";
|
|
@@ -6235,8 +6378,8 @@ function platformKey() {
|
|
|
6235
6378
|
);
|
|
6236
6379
|
}
|
|
6237
6380
|
function cacheDir(version) {
|
|
6238
|
-
const base = process.env.XDG_CACHE_HOME || (0,
|
|
6239
|
-
return (0,
|
|
6381
|
+
const base = process.env.XDG_CACHE_HOME || (0, import_node_path11.join)((0, import_node_os4.homedir)(), ".cache");
|
|
6382
|
+
return (0, import_node_path11.join)(base, "agentful", "engine", version);
|
|
6240
6383
|
}
|
|
6241
6384
|
async function fetchManifest() {
|
|
6242
6385
|
try {
|
|
@@ -6247,7 +6390,7 @@ async function fetchManifest() {
|
|
|
6247
6390
|
}
|
|
6248
6391
|
async function sha256File(path) {
|
|
6249
6392
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
6250
|
-
await (0,
|
|
6393
|
+
await (0, import_promises3.pipeline)((0, import_node_fs9.createReadStream)(path), hash);
|
|
6251
6394
|
return hash.digest("hex");
|
|
6252
6395
|
}
|
|
6253
6396
|
async function ensureEngine() {
|
|
@@ -6256,12 +6399,12 @@ async function ensureEngine() {
|
|
|
6256
6399
|
noticeIfOutdated(manifest);
|
|
6257
6400
|
const version = manifest?.engine_version || FALLBACK_ENGINE_VERSION;
|
|
6258
6401
|
const dir = cacheDir(version);
|
|
6259
|
-
const binPath = (0,
|
|
6260
|
-
if ((0,
|
|
6402
|
+
const binPath = (0, import_node_path11.join)(dir, ENGINE_BINARY);
|
|
6403
|
+
if ((0, import_node_fs9.existsSync)(binPath)) return binPath;
|
|
6261
6404
|
const artifact = manifest?.artifacts?.[key];
|
|
6262
6405
|
const url = artifact?.url || `${APP_URL}/cli/engine/${version}/${key}${key.startsWith("darwin") ? ".zip" : ".tar.gz"}`;
|
|
6263
|
-
(0,
|
|
6264
|
-
const archivePath = (0,
|
|
6406
|
+
(0, import_node_fs9.mkdirSync)(dir, { recursive: true });
|
|
6407
|
+
const archivePath = (0, import_node_path11.join)(dir, key.startsWith("darwin") ? "engine.zip" : "engine.tar.gz");
|
|
6265
6408
|
ui.step(`Preparing the ${brand.displayName} engine (first run only)\u2026`);
|
|
6266
6409
|
const resp = await fetch(url, {
|
|
6267
6410
|
redirect: "follow",
|
|
@@ -6275,11 +6418,11 @@ async function ensureEngine() {
|
|
|
6275
6418
|
`Could not download the engine (HTTP ${resp.status}). Check your connection and try again.`
|
|
6276
6419
|
);
|
|
6277
6420
|
}
|
|
6278
|
-
await (0,
|
|
6421
|
+
await (0, import_promises3.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0, import_node_fs9.createWriteStream)(archivePath));
|
|
6279
6422
|
if (artifact?.sha256) {
|
|
6280
6423
|
const actual = await sha256File(archivePath);
|
|
6281
6424
|
if (actual !== artifact.sha256) {
|
|
6282
|
-
(0,
|
|
6425
|
+
(0, import_node_fs9.rmSync)(archivePath, { force: true });
|
|
6283
6426
|
throw new ApiError(
|
|
6284
6427
|
0,
|
|
6285
6428
|
"engine_checksum_mismatch",
|
|
@@ -6288,7 +6431,7 @@ async function ensureEngine() {
|
|
|
6288
6431
|
}
|
|
6289
6432
|
}
|
|
6290
6433
|
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" });
|
|
6291
|
-
(0,
|
|
6434
|
+
(0, import_node_fs9.rmSync)(archivePath, { force: true });
|
|
6292
6435
|
if (extract.status !== 0) {
|
|
6293
6436
|
throw new ApiError(
|
|
6294
6437
|
0,
|
|
@@ -6296,24 +6439,24 @@ async function ensureEngine() {
|
|
|
6296
6439
|
`Could not unpack the engine (needs ${archivePath.endsWith(".zip") ? "unzip" : "tar"} on PATH).`
|
|
6297
6440
|
);
|
|
6298
6441
|
}
|
|
6299
|
-
const extracted = (0,
|
|
6300
|
-
if ((0,
|
|
6301
|
-
if (!(0,
|
|
6442
|
+
const extracted = (0, import_node_path11.join)(dir, "opencode");
|
|
6443
|
+
if ((0, import_node_fs9.existsSync)(extracted) && !(0, import_node_fs9.existsSync)(binPath)) (0, import_node_fs9.renameSync)(extracted, binPath);
|
|
6444
|
+
if (!(0, import_node_fs9.existsSync)(binPath)) {
|
|
6302
6445
|
throw new ApiError(0, "engine_extract_failed", "Engine archive did not contain the expected binary.");
|
|
6303
6446
|
}
|
|
6304
|
-
(0,
|
|
6447
|
+
(0, import_node_fs9.chmodSync)(binPath, 493);
|
|
6305
6448
|
ui.ok(`Engine ready.`);
|
|
6306
6449
|
console.log(paint.dim(" powered by opencode (MIT) \xB7 run `agentful licenses` for details"));
|
|
6307
6450
|
return binPath;
|
|
6308
6451
|
}
|
|
6309
6452
|
|
|
6310
6453
|
// src/lib/gatewayToken.ts
|
|
6311
|
-
var
|
|
6312
|
-
var
|
|
6313
|
-
var cachePath = () => (0,
|
|
6454
|
+
var import_node_fs10 = require("fs");
|
|
6455
|
+
var import_node_path12 = require("path");
|
|
6456
|
+
var cachePath = () => (0, import_node_path12.join)(configDir(), "gateway.json");
|
|
6314
6457
|
async function ensureGatewaySession(auth, projectId) {
|
|
6315
6458
|
try {
|
|
6316
|
-
const cached = JSON.parse((0,
|
|
6459
|
+
const cached = JSON.parse((0, import_node_fs10.readFileSync)(cachePath(), "utf8"));
|
|
6317
6460
|
if (cached?.token && cached.expires_at - Date.now() / 1e3 > 3600) {
|
|
6318
6461
|
return cached;
|
|
6319
6462
|
}
|
|
@@ -6324,18 +6467,18 @@ async function ensureGatewaySession(auth, projectId) {
|
|
|
6324
6467
|
body: projectId ? { project_id: projectId } : {},
|
|
6325
6468
|
timeoutMs: 3e4
|
|
6326
6469
|
});
|
|
6327
|
-
(0,
|
|
6328
|
-
(0,
|
|
6470
|
+
(0, import_node_fs10.mkdirSync)(configDir(), { recursive: true });
|
|
6471
|
+
(0, import_node_fs10.writeFileSync)(cachePath(), JSON.stringify(res, null, 2) + "\n", "utf8");
|
|
6329
6472
|
try {
|
|
6330
|
-
(0,
|
|
6473
|
+
(0, import_node_fs10.chmodSync)(cachePath(), 384);
|
|
6331
6474
|
} catch {
|
|
6332
6475
|
}
|
|
6333
6476
|
return res;
|
|
6334
6477
|
}
|
|
6335
6478
|
|
|
6336
6479
|
// src/lib/engineConfig.ts
|
|
6337
|
-
var
|
|
6338
|
-
var
|
|
6480
|
+
var import_node_fs12 = require("fs");
|
|
6481
|
+
var import_node_path14 = require("path");
|
|
6339
6482
|
var import_node_os5 = require("os");
|
|
6340
6483
|
|
|
6341
6484
|
// src/branding/agentful-theme.json
|
|
@@ -6478,22 +6621,22 @@ ${cmd.template}
|
|
|
6478
6621
|
}
|
|
6479
6622
|
|
|
6480
6623
|
// src/lib/tools.ts
|
|
6481
|
-
var
|
|
6482
|
-
var
|
|
6624
|
+
var import_node_fs11 = require("fs");
|
|
6625
|
+
var import_node_path13 = require("path");
|
|
6483
6626
|
function assetsDir() {
|
|
6484
|
-
const here = (0,
|
|
6485
|
-
for (const candidate of [(0,
|
|
6486
|
-
if ((0,
|
|
6627
|
+
const here = (0, import_node_path13.dirname)(process.argv[1] || "");
|
|
6628
|
+
for (const candidate of [(0, import_node_path13.join)(here, "..", "assets"), (0, import_node_path13.join)(here, "assets")]) {
|
|
6629
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(candidate, "tools", "imagegen.ts"))) return candidate;
|
|
6487
6630
|
}
|
|
6488
6631
|
return null;
|
|
6489
6632
|
}
|
|
6490
6633
|
function installEngineTools(configDir2) {
|
|
6491
6634
|
const assets = assetsDir();
|
|
6492
6635
|
if (!assets) return false;
|
|
6493
|
-
const target = (0,
|
|
6494
|
-
(0,
|
|
6636
|
+
const target = (0, import_node_path13.join)(configDir2, "tools");
|
|
6637
|
+
(0, import_node_fs11.mkdirSync)(target, { recursive: true });
|
|
6495
6638
|
try {
|
|
6496
|
-
(0,
|
|
6639
|
+
(0, import_node_fs11.cpSync)((0, import_node_path13.join)(assets, "tools"), target, { recursive: true });
|
|
6497
6640
|
return true;
|
|
6498
6641
|
} catch {
|
|
6499
6642
|
return false;
|
|
@@ -6675,7 +6818,9 @@ without an address. Read \`.agentful/project.json\` and give the full URL
|
|
|
6675
6818
|
\`https://app.agentful.dev/workspace/<userId>/<projectId>?view=backend\` \u2014 or
|
|
6676
6819
|
simply the command \`agentful backend\`, which opens exactly that page and
|
|
6677
6820
|
shows the live state. Declaring a backend never enables it; enabling is the
|
|
6678
|
-
user's conscious step in that tab
|
|
6821
|
+
user's conscious step \u2014 in that tab, or by answering the question
|
|
6822
|
+
\`agentful push\` asks once (it names both consequences; a non-interactive
|
|
6823
|
+
push never enables anything).
|
|
6679
6824
|
|
|
6680
6825
|
## Diagnosing failed pushes and cloud builds (hard rule)
|
|
6681
6826
|
|
|
@@ -6703,7 +6848,7 @@ var CLOUD_AGENT_PROMPT = `You are the Agentful Cloud build agent: everything you
|
|
|
6703
6848
|
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 (static files only). 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.";
|
|
6704
6849
|
function readAuthFile(path) {
|
|
6705
6850
|
try {
|
|
6706
|
-
return (0,
|
|
6851
|
+
return (0, import_node_fs12.readFileSync)(path, "utf8");
|
|
6707
6852
|
} catch {
|
|
6708
6853
|
return null;
|
|
6709
6854
|
}
|
|
@@ -6768,11 +6913,11 @@ function buildEngineConfig(opts) {
|
|
|
6768
6913
|
};
|
|
6769
6914
|
}
|
|
6770
6915
|
function engineXdg() {
|
|
6771
|
-
const root = (0,
|
|
6916
|
+
const root = (0, import_node_path14.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful");
|
|
6772
6917
|
return {
|
|
6773
|
-
configHome: (0,
|
|
6774
|
-
dataHome: (0,
|
|
6775
|
-
stateHome: (0,
|
|
6918
|
+
configHome: (0, import_node_path14.join)(root, "engine-config"),
|
|
6919
|
+
dataHome: (0, import_node_path14.join)(root, "engine-data"),
|
|
6920
|
+
stateHome: (0, import_node_path14.join)(root, "engine-state")
|
|
6776
6921
|
};
|
|
6777
6922
|
}
|
|
6778
6923
|
async function resolveTheme() {
|
|
@@ -6791,24 +6936,24 @@ async function resolveTheme() {
|
|
|
6791
6936
|
}
|
|
6792
6937
|
async function writeEngineSession(session, catalog, localProviders = {}, framework = "unknown", skillsInstruction = null, backendState) {
|
|
6793
6938
|
const xdg = engineXdg();
|
|
6794
|
-
const configDir2 = (0,
|
|
6795
|
-
const dataDir = (0,
|
|
6796
|
-
const themesDir = (0,
|
|
6797
|
-
const pluginsDir = (0,
|
|
6798
|
-
const commandsDir = (0,
|
|
6799
|
-
for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0,
|
|
6800
|
-
(0,
|
|
6939
|
+
const configDir2 = (0, import_node_path14.join)(xdg.configHome, "opencode");
|
|
6940
|
+
const dataDir = (0, import_node_path14.join)(xdg.dataHome, "opencode");
|
|
6941
|
+
const themesDir = (0, import_node_path14.join)(configDir2, "themes");
|
|
6942
|
+
const pluginsDir = (0, import_node_path14.join)(configDir2, "plugins");
|
|
6943
|
+
const commandsDir = (0, import_node_path14.join)(configDir2, "commands");
|
|
6944
|
+
for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0, import_node_path14.join)(xdg.stateHome, "opencode")]) {
|
|
6945
|
+
(0, import_node_fs12.mkdirSync)(dir, { recursive: true });
|
|
6801
6946
|
}
|
|
6802
6947
|
const imagegenAvailable = installEngineTools(configDir2) && session.img_on !== false;
|
|
6803
|
-
const cloudInstructionsPath = (0,
|
|
6804
|
-
(0,
|
|
6805
|
-
const skillsPath = (0,
|
|
6948
|
+
const cloudInstructionsPath = (0, import_node_path14.join)(configDir2, CLOUD_INSTRUCTIONS_FILENAME);
|
|
6949
|
+
(0, import_node_fs12.writeFileSync)(cloudInstructionsPath, renderCloudInstructions(framework, backendState));
|
|
6950
|
+
const skillsPath = (0, import_node_path14.join)(configDir2, "AGENTFUL_SKILLS.md");
|
|
6806
6951
|
const instructionPaths = [cloudInstructionsPath];
|
|
6807
6952
|
if (skillsInstruction) {
|
|
6808
|
-
(0,
|
|
6953
|
+
(0, import_node_fs12.writeFileSync)(skillsPath, skillsInstruction);
|
|
6809
6954
|
instructionPaths.push(skillsPath);
|
|
6810
6955
|
} else {
|
|
6811
|
-
(0,
|
|
6956
|
+
(0, import_node_fs12.rmSync)(skillsPath, { force: true });
|
|
6812
6957
|
}
|
|
6813
6958
|
const config = buildEngineConfig({
|
|
6814
6959
|
session,
|
|
@@ -6817,23 +6962,23 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
6817
6962
|
imagegenAvailable,
|
|
6818
6963
|
instructionPaths
|
|
6819
6964
|
});
|
|
6820
|
-
(0,
|
|
6821
|
-
const authPath2 = (0,
|
|
6822
|
-
(0,
|
|
6965
|
+
(0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(configDir2, "config.json"), JSON.stringify(config, null, 2));
|
|
6966
|
+
const authPath2 = (0, import_node_path14.join)(dataDir, "auth.json");
|
|
6967
|
+
(0, import_node_fs12.writeFileSync)(authPath2, mergedAuthJson(readAuthFile(authPath2), session.token));
|
|
6823
6968
|
const { brandingPluginSource: brandingPluginSource2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
|
|
6824
|
-
const pluginPath = (0,
|
|
6825
|
-
(0,
|
|
6826
|
-
(0,
|
|
6969
|
+
const pluginPath = (0, import_node_path14.join)(pluginsDir, "agentful-branding.tsx");
|
|
6970
|
+
(0, import_node_fs12.writeFileSync)(pluginPath, brandingPluginSource2());
|
|
6971
|
+
(0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(configDir2, "tui.json"), JSON.stringify({
|
|
6827
6972
|
theme: "agentful",
|
|
6828
6973
|
plugin: [`file://${pluginPath}`]
|
|
6829
6974
|
}, null, 2));
|
|
6830
|
-
(0,
|
|
6975
|
+
(0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(themesDir, "agentful.json"), JSON.stringify(await resolveTheme(), null, 2));
|
|
6831
6976
|
for (const name of Object.keys(SLASH_COMMANDS)) {
|
|
6832
|
-
(0,
|
|
6977
|
+
(0, import_node_fs12.writeFileSync)((0, import_node_path14.join)(commandsDir, `${name}.md`), commandMarkdown(name));
|
|
6833
6978
|
}
|
|
6834
6979
|
for (const legacy of ["xdg-config", "xdg-data", "xdg-state"]) {
|
|
6835
6980
|
try {
|
|
6836
|
-
(0,
|
|
6981
|
+
(0, import_node_fs12.rmSync)((0, import_node_path14.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful", legacy), { recursive: true, force: true });
|
|
6837
6982
|
} catch {
|
|
6838
6983
|
}
|
|
6839
6984
|
}
|
|
@@ -6841,8 +6986,8 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
6841
6986
|
}
|
|
6842
6987
|
|
|
6843
6988
|
// src/lib/skills.ts
|
|
6844
|
-
var
|
|
6845
|
-
var
|
|
6989
|
+
var import_node_fs13 = require("fs");
|
|
6990
|
+
var import_node_path15 = require("path");
|
|
6846
6991
|
|
|
6847
6992
|
// src/generated/skills.json
|
|
6848
6993
|
var skills_default = {
|
|
@@ -6911,7 +7056,7 @@ var SCAFFOLD_BY_FRAMEWORK = {
|
|
|
6911
7056
|
};
|
|
6912
7057
|
function hasVueDependency(rootDir) {
|
|
6913
7058
|
try {
|
|
6914
|
-
const pkg = JSON.parse((0,
|
|
7059
|
+
const pkg = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path15.join)(rootDir, "package.json"), "utf8"));
|
|
6915
7060
|
return Boolean({ ...pkg.dependencies, ...pkg.devDependencies }["vue"]);
|
|
6916
7061
|
} catch {
|
|
6917
7062
|
return false;
|
|
@@ -6941,7 +7086,7 @@ function renderSkillsInstruction(names) {
|
|
|
6941
7086
|
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";
|
|
6942
7087
|
}
|
|
6943
7088
|
function skillsInstructionFor(framework, rootDir) {
|
|
6944
|
-
if (!(0,
|
|
7089
|
+
if (!(0, import_node_fs13.existsSync)(rootDir)) return null;
|
|
6945
7090
|
return renderSkillsInstruction(selectSkills(framework, rootDir));
|
|
6946
7091
|
}
|
|
6947
7092
|
|
|
@@ -7056,15 +7201,15 @@ function decideLocalProviders(policy) {
|
|
|
7056
7201
|
}
|
|
7057
7202
|
|
|
7058
7203
|
// src/lib/localProviders.ts
|
|
7059
|
-
var
|
|
7060
|
-
var
|
|
7204
|
+
var import_node_fs14 = require("fs");
|
|
7205
|
+
var import_node_path16 = require("path");
|
|
7061
7206
|
var LOCAL_PROVIDERS_FILE = "local-providers.json";
|
|
7062
7207
|
function localProvidersPath() {
|
|
7063
|
-
return (0,
|
|
7208
|
+
return (0, import_node_path16.join)(configDir(), LOCAL_PROVIDERS_FILE);
|
|
7064
7209
|
}
|
|
7065
7210
|
function readLocalProviders() {
|
|
7066
7211
|
try {
|
|
7067
|
-
const raw = JSON.parse((0,
|
|
7212
|
+
const raw = JSON.parse((0, import_node_fs14.readFileSync)(localProvidersPath(), "utf8"));
|
|
7068
7213
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
7069
7214
|
const map = raw.providers && typeof raw.providers === "object" ? raw.providers : raw;
|
|
7070
7215
|
const usable = {};
|
|
@@ -7099,8 +7244,8 @@ function resolveLocalProviders(policy) {
|
|
|
7099
7244
|
}
|
|
7100
7245
|
function writeLocalProvidersExample() {
|
|
7101
7246
|
const path = localProvidersPath();
|
|
7102
|
-
if ((0,
|
|
7103
|
-
(0,
|
|
7247
|
+
if ((0, import_node_fs14.existsSync)(path)) return path;
|
|
7248
|
+
(0, import_node_fs14.mkdirSync)(configDir(), { recursive: true });
|
|
7104
7249
|
const example = {
|
|
7105
7250
|
_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.',
|
|
7106
7251
|
_anthropic: {
|
|
@@ -7110,21 +7255,21 @@ function writeLocalProvidersExample() {
|
|
|
7110
7255
|
models: { "claude-sonnet-4-5": { name: "Claude Sonnet 4.5 (my key)" } }
|
|
7111
7256
|
}
|
|
7112
7257
|
};
|
|
7113
|
-
(0,
|
|
7258
|
+
(0, import_node_fs14.writeFileSync)(path, JSON.stringify(example, null, 2) + "\n", "utf8");
|
|
7114
7259
|
try {
|
|
7115
|
-
(0,
|
|
7260
|
+
(0, import_node_fs14.chmodSync)(path, 384);
|
|
7116
7261
|
} catch {
|
|
7117
7262
|
}
|
|
7118
7263
|
return path;
|
|
7119
7264
|
}
|
|
7120
7265
|
|
|
7121
7266
|
// src/lib/sessions.ts
|
|
7122
|
-
var
|
|
7123
|
-
var
|
|
7267
|
+
var import_node_fs15 = require("fs");
|
|
7268
|
+
var import_node_path17 = require("path");
|
|
7124
7269
|
var import_node_child_process4 = require("child_process");
|
|
7125
7270
|
function lastSessionForDirectory(cwd = process.cwd()) {
|
|
7126
|
-
const dbPath = (0,
|
|
7127
|
-
if (!(0,
|
|
7271
|
+
const dbPath = (0, import_node_path17.join)(engineXdg().dataHome, "opencode", "opencode.db");
|
|
7272
|
+
if (!(0, import_node_fs15.existsSync)(dbPath)) return null;
|
|
7128
7273
|
const escaped = cwd.replace(/'/g, "''");
|
|
7129
7274
|
const res = (0, import_node_child_process4.spawnSync)(
|
|
7130
7275
|
"sqlite3",
|
|
@@ -7216,7 +7361,7 @@ async function tuiCommand(opts = {}) {
|
|
|
7216
7361
|
...process.env,
|
|
7217
7362
|
// Slash commands run `agentful …` through the agent's bash tool, which
|
|
7218
7363
|
// has no access to the user's shell aliases.
|
|
7219
|
-
PATH: `${binDir}${
|
|
7364
|
+
PATH: `${binDir}${import_node_path18.delimiter}${process.env.PATH || ""}`,
|
|
7220
7365
|
XDG_CONFIG_HOME: xdg.configHome,
|
|
7221
7366
|
XDG_DATA_HOME: xdg.dataHome,
|
|
7222
7367
|
XDG_STATE_HOME: xdg.stateHome,
|
|
@@ -7321,28 +7466,28 @@ async function shareCommand(opts) {
|
|
|
7321
7466
|
}
|
|
7322
7467
|
|
|
7323
7468
|
// src/commands/pull.ts
|
|
7324
|
-
var
|
|
7325
|
-
var
|
|
7469
|
+
var import_node_fs16 = require("fs");
|
|
7470
|
+
var import_node_path19 = require("path");
|
|
7326
7471
|
init_branding();
|
|
7327
7472
|
init_branding();
|
|
7328
7473
|
function isProbablyBase64Binary(path) {
|
|
7329
7474
|
return /\.(png|jpe?g|gif|webp|ico|woff2?|ttf|otf|eot|pdf|zip|mp[34]|webm|avif)$/i.test(path);
|
|
7330
7475
|
}
|
|
7331
7476
|
function writeEntry(root, rel, value) {
|
|
7332
|
-
const target = (0,
|
|
7333
|
-
(0,
|
|
7477
|
+
const target = (0, import_node_path19.join)(root, rel);
|
|
7478
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path19.dirname)(target), { recursive: true });
|
|
7334
7479
|
const content = typeof value === "object" && value !== null && "content" in value ? String(value.content) : String(value ?? "");
|
|
7335
7480
|
if (isProbablyBase64Binary(rel)) {
|
|
7336
|
-
(0,
|
|
7481
|
+
(0, import_node_fs16.writeFileSync)(target, Buffer.from(content, "base64"));
|
|
7337
7482
|
} else {
|
|
7338
|
-
(0,
|
|
7483
|
+
(0, import_node_fs16.writeFileSync)(target, content, "utf8");
|
|
7339
7484
|
}
|
|
7340
7485
|
}
|
|
7341
7486
|
async function pullCommand(opts) {
|
|
7342
7487
|
console.log(banner());
|
|
7343
7488
|
const auth = await ensureAuth();
|
|
7344
7489
|
const project = requireProject();
|
|
7345
|
-
const nonHidden = (0,
|
|
7490
|
+
const nonHidden = (0, import_node_fs16.readdirSync)(process.cwd()).filter((n) => n !== ".agentful" && !n.startsWith("."));
|
|
7346
7491
|
if (nonHidden.length > 0 && !opts.force) {
|
|
7347
7492
|
throw new ApiError(
|
|
7348
7493
|
0,
|
|
@@ -7366,9 +7511,9 @@ async function pullCommand(opts) {
|
|
|
7366
7511
|
ui.warn(`Skipped ${rel} (HTTP ${resp.status})`);
|
|
7367
7512
|
continue;
|
|
7368
7513
|
}
|
|
7369
|
-
const target = (0,
|
|
7370
|
-
(0,
|
|
7371
|
-
(0,
|
|
7514
|
+
const target = (0, import_node_path19.join)(process.cwd(), rel);
|
|
7515
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path19.dirname)(target), { recursive: true });
|
|
7516
|
+
(0, import_node_fs16.writeFileSync)(target, Buffer.from(await resp.arrayBuffer()));
|
|
7372
7517
|
written++;
|
|
7373
7518
|
}
|
|
7374
7519
|
} else if (data.files) {
|
|
@@ -7522,7 +7667,7 @@ program2.command("login").description("Sign in to your Agentful account (device
|
|
|
7522
7667
|
program2.command("logout").description("Remove the stored credentials").action(run(logoutCommand));
|
|
7523
7668
|
program2.command("whoami").description("Show the signed-in account").action(run(whoamiCommand));
|
|
7524
7669
|
program2.command("init").description("Create (or link) the Agentful cloud project for this directory").argument("[directory]", "with --template: new folder to scaffold into (created for you)").option("--link <projectId>", "link an existing project instead of creating one").option("--title <title>", "project title (skips the prompt)").option("--template <framework>", "scaffold from a platform starter (nextjs, react, vue, vanilla)").action(run((directory, opts) => initCommand(opts, directory)));
|
|
7525
|
-
program2.command("push").description("Upload this project and get a live preview URL").option("--prebuilt", "upload a locally built output instead of building in the cloud").option("--dir <path>", "built-output directory for --prebuilt (default: auto-detect)").option("--force", "push even when the pre-upload compatibility check finds blocking issues").action(run((opts) => pushCommand(opts)));
|
|
7670
|
+
program2.command("push").description("Upload this project and get a live preview URL").option("--prebuilt", "upload a locally built output instead of building in the cloud").option("--dir <path>", "built-output directory for --prebuilt (default: auto-detect)").option("--force", "push even when the pre-upload compatibility check finds blocking issues").option("-y, --yes", "enable the declared managed database without asking (CI); a non-interactive push never enables it").action(run((opts) => pushCommand(opts)));
|
|
7526
7671
|
program2.command("build-status").description("Show the cloud's record of the last build (the real error on failures)").action(run(buildStatusCommand));
|
|
7527
7672
|
program2.command("backend").description("Open this project's Backend tab (managed DB + server actions) in the browser").action(run(backendCommand));
|
|
7528
7673
|
program2.command("open").description("Open the live preview in the browser").action(run(openCommand));
|