agentful 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +197 -108
- 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.2.
|
|
3047
|
+
VERSION = "0.2.2" ? "0.2.2" : null.version;
|
|
3048
3048
|
brand = {
|
|
3049
3049
|
name: "agentful",
|
|
3050
3050
|
// the command users type
|
|
@@ -4395,7 +4395,8 @@ function materializeStarter(name, targetDir, projectName) {
|
|
|
4395
4395
|
throw new ApiError(
|
|
4396
4396
|
0,
|
|
4397
4397
|
"directory_not_empty",
|
|
4398
|
-
`This directory is not empty (found ${blockers.slice(0, 3).join(", ")}${blockers.length > 3 ? ", \u2026" : ""}). \`init --template\` scaffolds into an empty directory only \u2014 it never overwrites your files
|
|
4398
|
+
`This directory is not empty (found ${blockers.slice(0, 3).join(", ")}${blockers.length > 3 ? ", \u2026" : ""}). \`init --template\` scaffolds into an empty directory only \u2014 it never overwrites your files.
|
|
4399
|
+
Pass a new folder name instead: \`agentful init --template ${name} my-app\` (creates it for you).`
|
|
4399
4400
|
);
|
|
4400
4401
|
}
|
|
4401
4402
|
let written = 0;
|
|
@@ -4419,16 +4420,15 @@ function materializeStarter(name, targetDir, projectName) {
|
|
|
4419
4420
|
function slugify(value) {
|
|
4420
4421
|
return value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
4421
4422
|
}
|
|
4423
|
+
function prepareScaffoldDirectory(baseDir, directory) {
|
|
4424
|
+
const target = (0, import_node_path4.resolve)(baseDir, directory);
|
|
4425
|
+
(0, import_node_fs3.mkdirSync)(target, { recursive: true });
|
|
4426
|
+
return target;
|
|
4427
|
+
}
|
|
4422
4428
|
|
|
4423
4429
|
// src/commands/init.ts
|
|
4424
|
-
async function initCommand(opts) {
|
|
4430
|
+
async function initCommand(opts, directory) {
|
|
4425
4431
|
console.log(banner());
|
|
4426
|
-
const existing = readProjectConfig();
|
|
4427
|
-
if (existing) {
|
|
4428
|
-
ui.info(`Already initialized (project ${existing.projectId} \u2014 "${existing.title}").`);
|
|
4429
|
-
ui.info("Delete .agentful/project.json to re-initialize.");
|
|
4430
|
-
return;
|
|
4431
|
-
}
|
|
4432
4432
|
if (opts.template && opts.link) {
|
|
4433
4433
|
throw new ApiError(
|
|
4434
4434
|
0,
|
|
@@ -4436,6 +4436,22 @@ async function initCommand(opts) {
|
|
|
4436
4436
|
"--template scaffolds a new project and cannot be combined with --link."
|
|
4437
4437
|
);
|
|
4438
4438
|
}
|
|
4439
|
+
if (directory && !opts.template) {
|
|
4440
|
+
throw new ApiError(
|
|
4441
|
+
0,
|
|
4442
|
+
"invalid_options",
|
|
4443
|
+
"A target directory only makes sense with --template \u2014 plain `init` links the directory you are in."
|
|
4444
|
+
);
|
|
4445
|
+
}
|
|
4446
|
+
if (opts.template && directory) {
|
|
4447
|
+
process.chdir(prepareScaffoldDirectory(process.cwd(), directory));
|
|
4448
|
+
}
|
|
4449
|
+
const existing = readProjectConfig();
|
|
4450
|
+
if (existing) {
|
|
4451
|
+
ui.info(`Already initialized (project ${existing.projectId} \u2014 "${existing.title}").`);
|
|
4452
|
+
ui.info("Delete .agentful/project.json to re-initialize.");
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4439
4455
|
if (opts.template) {
|
|
4440
4456
|
const title2 = opts.title?.trim() || (0, import_node_path5.basename)(process.cwd());
|
|
4441
4457
|
ui.step(`Scaffolding from the ${opts.template} starter\u2026`);
|
|
@@ -4465,6 +4481,7 @@ async function initCommand(opts) {
|
|
|
4465
4481
|
const config = await createProject(auth, title);
|
|
4466
4482
|
ui.ok(`Project created (${config.projectId}). Next: \`agentful push\``);
|
|
4467
4483
|
if (opts.template) {
|
|
4484
|
+
if (directory) ui.info(`Next: \`cd ${directory}\` \u2014 the project lives there now.`);
|
|
4468
4485
|
ui.info("Run `npm install` before local dev; `agentful push` builds in the cloud either way.");
|
|
4469
4486
|
ui.info(`Or start the coding agent right away: \`agentful\` (templates: ${STARTER_NAMES.join(", ")}).`);
|
|
4470
4487
|
}
|
|
@@ -5404,9 +5421,9 @@ var contract_default = {
|
|
|
5404
5421
|
details: "raw build output excerpt"
|
|
5405
5422
|
},
|
|
5406
5423
|
adopted_by: {
|
|
5407
|
-
build_engine: ["status", "timestamp", "error", "details", "framework"],
|
|
5408
|
-
executor: ["status", "timestamp", "phase", "error"],
|
|
5409
|
-
$comment: "
|
|
5424
|
+
build_engine: ["schema_version", "build_id", "started_at", "status", "timestamp", "phase", "error", "details", "framework"],
|
|
5425
|
+
executor: ["schema_version", "build_id", "started_at", "status", "timestamp", "phase", "error"],
|
|
5426
|
+
$comment: "Both builders write the attempt identity since AP4/AP5 (2026-08-18); failures carry phase codes and \u2014 for contract violations \u2014 code/reason/hints. The engine additionally writes a running record at start; the executor has no separate build-start moment (started_at is the turn start) and writes no running record. The CLI may graduate from timestamp freshness to identity-based polling for the ENGINE path."
|
|
5410
5427
|
}
|
|
5411
5428
|
}
|
|
5412
5429
|
};
|
|
@@ -5590,6 +5607,38 @@ function runPreflight(rootDir) {
|
|
|
5590
5607
|
return { framework, issues, warnings };
|
|
5591
5608
|
}
|
|
5592
5609
|
|
|
5610
|
+
// src/lib/backendDecl.ts
|
|
5611
|
+
var import_node_fs6 = require("fs");
|
|
5612
|
+
var import_node_path8 = require("path");
|
|
5613
|
+
function readBackendDeclaration(dir = process.cwd()) {
|
|
5614
|
+
const path = (0, import_node_path8.join)(dir, ".agentful", "backend.json");
|
|
5615
|
+
if (!(0, import_node_fs6.existsSync)(path)) return null;
|
|
5616
|
+
try {
|
|
5617
|
+
const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf8"));
|
|
5618
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
5619
|
+
const decl = {
|
|
5620
|
+
schema_version: Number(parsed.schema_version) || 1,
|
|
5621
|
+
managed_db: Boolean(parsed.managed_db),
|
|
5622
|
+
actions: Array.isArray(parsed.actions) ? parsed.actions.filter((a) => typeof a === "string") : [],
|
|
5623
|
+
contract_doc: typeof parsed.contract_doc === "string" ? parsed.contract_doc : void 0
|
|
5624
|
+
};
|
|
5625
|
+
if (!decl.managed_db && decl.actions.length === 0) return null;
|
|
5626
|
+
return decl;
|
|
5627
|
+
} catch {
|
|
5628
|
+
return null;
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
function describeBackendDeclaration(decl) {
|
|
5632
|
+
const parts = [];
|
|
5633
|
+
if (decl.managed_db) parts.push("managed DB");
|
|
5634
|
+
if (decl.actions && decl.actions.length > 0) parts.push(`${decl.actions.length} server action(s)`);
|
|
5635
|
+
const base = parts.join(" + ") || "managed backend";
|
|
5636
|
+
return decl.contract_doc ? `${base} (contract: ${decl.contract_doc})` : base;
|
|
5637
|
+
}
|
|
5638
|
+
function backendTabUrl(userId, projectId) {
|
|
5639
|
+
return `${APP_URL}/workspace/${userId}/${projectId}?view=backend`;
|
|
5640
|
+
}
|
|
5641
|
+
|
|
5593
5642
|
// src/lib/buildStatus.ts
|
|
5594
5643
|
init_branding();
|
|
5595
5644
|
var DIAGNOSIS_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
@@ -5715,6 +5764,10 @@ async function pushCommand(opts) {
|
|
|
5715
5764
|
console.log("");
|
|
5716
5765
|
ui.ok(`Live preview: ${ui.url(url)}`);
|
|
5717
5766
|
ui.info(`Manage in the browser: ${ui.url(`https://app.agentful.dev/workspace/${userId}/${projectId}`)}`);
|
|
5767
|
+
const backend = readBackendDeclaration();
|
|
5768
|
+
if (backend) {
|
|
5769
|
+
ui.info(`Declared managed backend: ${describeBackendDeclaration(backend)} \u2014 enable/manage it in the Backend tab: \`agentful backend\` takes you there.`);
|
|
5770
|
+
}
|
|
5718
5771
|
}
|
|
5719
5772
|
async function pollBuild(token, userId, projectId, startedAtMs) {
|
|
5720
5773
|
const deadline = Date.now() + 10 * 60 * 1e3;
|
|
@@ -5800,6 +5853,24 @@ async function buildStatusCommand() {
|
|
|
5800
5853
|
}
|
|
5801
5854
|
}
|
|
5802
5855
|
|
|
5856
|
+
// src/commands/backend.ts
|
|
5857
|
+
init_branding();
|
|
5858
|
+
async function backendCommand() {
|
|
5859
|
+
console.log(banner());
|
|
5860
|
+
const project = requireProject();
|
|
5861
|
+
const decl = readBackendDeclaration();
|
|
5862
|
+
if (decl) {
|
|
5863
|
+
ui.info(`This project declares: ${describeBackendDeclaration(decl)}.`);
|
|
5864
|
+
ui.info("Declared in code is not enabled on the platform \u2014 that happens in the Backend tab.");
|
|
5865
|
+
}
|
|
5866
|
+
const url = backendTabUrl(project.userId, project.projectId);
|
|
5867
|
+
ui.step(`Opening the Backend tab: ${ui.url(url)}`);
|
|
5868
|
+
if (!openInBrowser(url)) {
|
|
5869
|
+
ui.info("Could not launch a browser \u2014 open this URL manually:");
|
|
5870
|
+
ui.info(ui.url(url));
|
|
5871
|
+
}
|
|
5872
|
+
}
|
|
5873
|
+
|
|
5803
5874
|
// src/commands/open.ts
|
|
5804
5875
|
init_branding();
|
|
5805
5876
|
async function openCommand() {
|
|
@@ -5816,15 +5887,15 @@ async function openCommand() {
|
|
|
5816
5887
|
|
|
5817
5888
|
// src/commands/tui.ts
|
|
5818
5889
|
var import_node_child_process5 = require("child_process");
|
|
5819
|
-
var
|
|
5890
|
+
var import_node_path17 = require("path");
|
|
5820
5891
|
|
|
5821
5892
|
// src/lib/binWrapper.ts
|
|
5822
|
-
var
|
|
5823
|
-
var
|
|
5893
|
+
var import_node_fs7 = require("fs");
|
|
5894
|
+
var import_node_path9 = require("path");
|
|
5824
5895
|
var import_node_os3 = require("os");
|
|
5825
5896
|
function ensureCliOnPath() {
|
|
5826
|
-
const binDir = (0,
|
|
5827
|
-
(0,
|
|
5897
|
+
const binDir = (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".local", "share", "agentful", "bin");
|
|
5898
|
+
(0, import_node_fs7.mkdirSync)(binDir, { recursive: true });
|
|
5828
5899
|
const entry = process.argv[1];
|
|
5829
5900
|
if (!entry) return binDir;
|
|
5830
5901
|
const restore = (name) => {
|
|
@@ -5833,8 +5904,8 @@ function ensureCliOnPath() {
|
|
|
5833
5904
|
` : `export ${name}=${JSON.stringify(original)}
|
|
5834
5905
|
`;
|
|
5835
5906
|
};
|
|
5836
|
-
const wrapper = (0,
|
|
5837
|
-
(0,
|
|
5907
|
+
const wrapper = (0, import_node_path9.join)(binDir, "agentful");
|
|
5908
|
+
(0, import_node_fs7.writeFileSync)(
|
|
5838
5909
|
wrapper,
|
|
5839
5910
|
`#!/bin/sh
|
|
5840
5911
|
# Generated by the Agentful CLI so the coding agent can run \`agentful \u2026\`.
|
|
@@ -5844,7 +5915,7 @@ function ensureCliOnPath() {
|
|
|
5844
5915
|
"utf8"
|
|
5845
5916
|
);
|
|
5846
5917
|
try {
|
|
5847
|
-
(0,
|
|
5918
|
+
(0, import_node_fs7.chmodSync)(wrapper, 493);
|
|
5848
5919
|
} catch {
|
|
5849
5920
|
}
|
|
5850
5921
|
return binDir;
|
|
@@ -5854,9 +5925,9 @@ function ensureCliOnPath() {
|
|
|
5854
5925
|
init_branding();
|
|
5855
5926
|
|
|
5856
5927
|
// src/lib/engine.ts
|
|
5857
|
-
var
|
|
5928
|
+
var import_node_fs8 = require("fs");
|
|
5858
5929
|
var import_node_crypto = require("crypto");
|
|
5859
|
-
var
|
|
5930
|
+
var import_node_path10 = require("path");
|
|
5860
5931
|
var import_node_os4 = require("os");
|
|
5861
5932
|
var import_node_child_process3 = require("child_process");
|
|
5862
5933
|
var import_node_stream = require("stream");
|
|
@@ -5897,8 +5968,8 @@ function platformKey() {
|
|
|
5897
5968
|
);
|
|
5898
5969
|
}
|
|
5899
5970
|
function cacheDir(version) {
|
|
5900
|
-
const base = process.env.XDG_CACHE_HOME || (0,
|
|
5901
|
-
return (0,
|
|
5971
|
+
const base = process.env.XDG_CACHE_HOME || (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".cache");
|
|
5972
|
+
return (0, import_node_path10.join)(base, "agentful", "engine", version);
|
|
5902
5973
|
}
|
|
5903
5974
|
async function fetchManifest() {
|
|
5904
5975
|
try {
|
|
@@ -5909,7 +5980,7 @@ async function fetchManifest() {
|
|
|
5909
5980
|
}
|
|
5910
5981
|
async function sha256File(path) {
|
|
5911
5982
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
5912
|
-
await (0, import_promises2.pipeline)((0,
|
|
5983
|
+
await (0, import_promises2.pipeline)((0, import_node_fs8.createReadStream)(path), hash);
|
|
5913
5984
|
return hash.digest("hex");
|
|
5914
5985
|
}
|
|
5915
5986
|
async function ensureEngine() {
|
|
@@ -5918,12 +5989,12 @@ async function ensureEngine() {
|
|
|
5918
5989
|
noticeIfOutdated(manifest);
|
|
5919
5990
|
const version = manifest?.engine_version || FALLBACK_ENGINE_VERSION;
|
|
5920
5991
|
const dir = cacheDir(version);
|
|
5921
|
-
const binPath = (0,
|
|
5922
|
-
if ((0,
|
|
5992
|
+
const binPath = (0, import_node_path10.join)(dir, ENGINE_BINARY);
|
|
5993
|
+
if ((0, import_node_fs8.existsSync)(binPath)) return binPath;
|
|
5923
5994
|
const artifact = manifest?.artifacts?.[key];
|
|
5924
5995
|
const url = artifact?.url || `${APP_URL}/cli/engine/${version}/${key}${key.startsWith("darwin") ? ".zip" : ".tar.gz"}`;
|
|
5925
|
-
(0,
|
|
5926
|
-
const archivePath = (0,
|
|
5996
|
+
(0, import_node_fs8.mkdirSync)(dir, { recursive: true });
|
|
5997
|
+
const archivePath = (0, import_node_path10.join)(dir, key.startsWith("darwin") ? "engine.zip" : "engine.tar.gz");
|
|
5927
5998
|
ui.step(`Preparing the ${brand.displayName} engine (first run only)\u2026`);
|
|
5928
5999
|
const resp = await fetch(url, {
|
|
5929
6000
|
redirect: "follow",
|
|
@@ -5937,11 +6008,11 @@ async function ensureEngine() {
|
|
|
5937
6008
|
`Could not download the engine (HTTP ${resp.status}). Check your connection and try again.`
|
|
5938
6009
|
);
|
|
5939
6010
|
}
|
|
5940
|
-
await (0, import_promises2.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0,
|
|
6011
|
+
await (0, import_promises2.pipeline)(import_node_stream.Readable.fromWeb(resp.body), (0, import_node_fs8.createWriteStream)(archivePath));
|
|
5941
6012
|
if (artifact?.sha256) {
|
|
5942
6013
|
const actual = await sha256File(archivePath);
|
|
5943
6014
|
if (actual !== artifact.sha256) {
|
|
5944
|
-
(0,
|
|
6015
|
+
(0, import_node_fs8.rmSync)(archivePath, { force: true });
|
|
5945
6016
|
throw new ApiError(
|
|
5946
6017
|
0,
|
|
5947
6018
|
"engine_checksum_mismatch",
|
|
@@ -5950,7 +6021,7 @@ async function ensureEngine() {
|
|
|
5950
6021
|
}
|
|
5951
6022
|
}
|
|
5952
6023
|
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" });
|
|
5953
|
-
(0,
|
|
6024
|
+
(0, import_node_fs8.rmSync)(archivePath, { force: true });
|
|
5954
6025
|
if (extract.status !== 0) {
|
|
5955
6026
|
throw new ApiError(
|
|
5956
6027
|
0,
|
|
@@ -5958,24 +6029,24 @@ async function ensureEngine() {
|
|
|
5958
6029
|
`Could not unpack the engine (needs ${archivePath.endsWith(".zip") ? "unzip" : "tar"} on PATH).`
|
|
5959
6030
|
);
|
|
5960
6031
|
}
|
|
5961
|
-
const extracted = (0,
|
|
5962
|
-
if ((0,
|
|
5963
|
-
if (!(0,
|
|
6032
|
+
const extracted = (0, import_node_path10.join)(dir, "opencode");
|
|
6033
|
+
if ((0, import_node_fs8.existsSync)(extracted) && !(0, import_node_fs8.existsSync)(binPath)) (0, import_node_fs8.renameSync)(extracted, binPath);
|
|
6034
|
+
if (!(0, import_node_fs8.existsSync)(binPath)) {
|
|
5964
6035
|
throw new ApiError(0, "engine_extract_failed", "Engine archive did not contain the expected binary.");
|
|
5965
6036
|
}
|
|
5966
|
-
(0,
|
|
6037
|
+
(0, import_node_fs8.chmodSync)(binPath, 493);
|
|
5967
6038
|
ui.ok(`Engine ready.`);
|
|
5968
6039
|
console.log(paint.dim(" powered by opencode (MIT) \xB7 run `agentful licenses` for details"));
|
|
5969
6040
|
return binPath;
|
|
5970
6041
|
}
|
|
5971
6042
|
|
|
5972
6043
|
// src/lib/gatewayToken.ts
|
|
5973
|
-
var
|
|
5974
|
-
var
|
|
5975
|
-
var cachePath = () => (0,
|
|
6044
|
+
var import_node_fs9 = require("fs");
|
|
6045
|
+
var import_node_path11 = require("path");
|
|
6046
|
+
var cachePath = () => (0, import_node_path11.join)(configDir(), "gateway.json");
|
|
5976
6047
|
async function ensureGatewaySession(auth, projectId) {
|
|
5977
6048
|
try {
|
|
5978
|
-
const cached = JSON.parse((0,
|
|
6049
|
+
const cached = JSON.parse((0, import_node_fs9.readFileSync)(cachePath(), "utf8"));
|
|
5979
6050
|
if (cached?.token && cached.expires_at - Date.now() / 1e3 > 3600) {
|
|
5980
6051
|
return cached;
|
|
5981
6052
|
}
|
|
@@ -5986,18 +6057,18 @@ async function ensureGatewaySession(auth, projectId) {
|
|
|
5986
6057
|
body: projectId ? { project_id: projectId } : {},
|
|
5987
6058
|
timeoutMs: 3e4
|
|
5988
6059
|
});
|
|
5989
|
-
(0,
|
|
5990
|
-
(0,
|
|
6060
|
+
(0, import_node_fs9.mkdirSync)(configDir(), { recursive: true });
|
|
6061
|
+
(0, import_node_fs9.writeFileSync)(cachePath(), JSON.stringify(res, null, 2) + "\n", "utf8");
|
|
5991
6062
|
try {
|
|
5992
|
-
(0,
|
|
6063
|
+
(0, import_node_fs9.chmodSync)(cachePath(), 384);
|
|
5993
6064
|
} catch {
|
|
5994
6065
|
}
|
|
5995
6066
|
return res;
|
|
5996
6067
|
}
|
|
5997
6068
|
|
|
5998
6069
|
// src/lib/engineConfig.ts
|
|
5999
|
-
var
|
|
6000
|
-
var
|
|
6070
|
+
var import_node_fs11 = require("fs");
|
|
6071
|
+
var import_node_path13 = require("path");
|
|
6001
6072
|
var import_node_os5 = require("os");
|
|
6002
6073
|
|
|
6003
6074
|
// src/branding/agentful-theme.json
|
|
@@ -6106,6 +6177,10 @@ var SLASH_COMMANDS = {
|
|
|
6106
6177
|
description: `${brand.displayName}: show the last cloud build result`,
|
|
6107
6178
|
template: "Run `agentful build-status` from the project root using the bash tool and report what it prints: status, phase, framework, when it was recorded, and the error/details verbatim if it failed. That record is the only source of truth about the cloud build \u2014 do not speculate beyond it. " + NEEDS_A_PUSH
|
|
6108
6179
|
},
|
|
6180
|
+
backend: {
|
|
6181
|
+
description: `${brand.displayName}: open the Backend tab (managed DB + server actions)`,
|
|
6182
|
+
template: "Run `agentful backend` from the project root using the bash tool and report the URL it opened. If it prints a declared backend (managed DB / server actions), summarize that and remind me that declared-in-code serves nothing until enabled in that tab. " + NEEDS_A_PUSH
|
|
6183
|
+
},
|
|
6109
6184
|
preview: {
|
|
6110
6185
|
description: `${brand.displayName}: open the live preview in the browser`,
|
|
6111
6186
|
template: "Run `agentful open` from the project root using the bash tool and report the URL it opened. Note that `open` neither builds nor uploads. " + NEEDS_A_PUSH
|
|
@@ -6136,22 +6211,22 @@ ${cmd.template}
|
|
|
6136
6211
|
}
|
|
6137
6212
|
|
|
6138
6213
|
// src/lib/tools.ts
|
|
6139
|
-
var
|
|
6140
|
-
var
|
|
6214
|
+
var import_node_fs10 = require("fs");
|
|
6215
|
+
var import_node_path12 = require("path");
|
|
6141
6216
|
function assetsDir() {
|
|
6142
|
-
const here = (0,
|
|
6143
|
-
for (const candidate of [(0,
|
|
6144
|
-
if ((0,
|
|
6217
|
+
const here = (0, import_node_path12.dirname)(process.argv[1] || "");
|
|
6218
|
+
for (const candidate of [(0, import_node_path12.join)(here, "..", "assets"), (0, import_node_path12.join)(here, "assets")]) {
|
|
6219
|
+
if ((0, import_node_fs10.existsSync)((0, import_node_path12.join)(candidate, "tools", "imagegen.ts"))) return candidate;
|
|
6145
6220
|
}
|
|
6146
6221
|
return null;
|
|
6147
6222
|
}
|
|
6148
6223
|
function installEngineTools(configDir2) {
|
|
6149
6224
|
const assets = assetsDir();
|
|
6150
6225
|
if (!assets) return false;
|
|
6151
|
-
const target = (0,
|
|
6152
|
-
(0,
|
|
6226
|
+
const target = (0, import_node_path12.join)(configDir2, "tools");
|
|
6227
|
+
(0, import_node_fs10.mkdirSync)(target, { recursive: true });
|
|
6153
6228
|
try {
|
|
6154
|
-
(0,
|
|
6229
|
+
(0, import_node_fs10.cpSync)((0, import_node_path12.join)(assets, "tools"), target, { recursive: true });
|
|
6155
6230
|
return true;
|
|
6156
6231
|
} catch {
|
|
6157
6232
|
return false;
|
|
@@ -6229,6 +6304,19 @@ statically evaluable; prefer client-side fetch or Managed Server Actions.
|
|
|
6229
6304
|
(b) an external backend called from the client. Never a bundled server
|
|
6230
6305
|
process, and never a script the user must run locally to produce the result.
|
|
6231
6306
|
|
|
6307
|
+
When you design a managed backend (DB schema, server actions), also write the
|
|
6308
|
+
machine-readable declaration \`.agentful/backend.json\`:
|
|
6309
|
+
\`{"schema_version": 1, "managed_db": true, "actions": ["<action-name>", \u2026], "contract_doc": "docs/backend-contract.md"}\`
|
|
6310
|
+
\u2014 \`agentful push\` and \`agentful backend\` use it to tell the user honestly
|
|
6311
|
+
what is declared in code but not yet enabled on the platform.
|
|
6312
|
+
|
|
6313
|
+
When you point the user at the Backend tab, NEVER say "the Backend tab"
|
|
6314
|
+
without an address. Read \`.agentful/project.json\` and give the full URL
|
|
6315
|
+
\`https://app.agentful.dev/workspace/<userId>/<projectId>?view=backend\` \u2014 or
|
|
6316
|
+
simply the command \`agentful backend\`, which opens exactly that page.
|
|
6317
|
+
Declaring a backend never enables it; enabling is the user's conscious step
|
|
6318
|
+
in that tab.
|
|
6319
|
+
|
|
6232
6320
|
## Diagnosing failed pushes and cloud builds (hard rule)
|
|
6233
6321
|
|
|
6234
6322
|
Diagnose **only from evidence**: the preflight output of \`agentful push\`, and
|
|
@@ -6296,11 +6384,11 @@ function buildEngineConfig(opts) {
|
|
|
6296
6384
|
};
|
|
6297
6385
|
}
|
|
6298
6386
|
function engineXdg() {
|
|
6299
|
-
const root = (0,
|
|
6387
|
+
const root = (0, import_node_path13.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful");
|
|
6300
6388
|
return {
|
|
6301
|
-
configHome: (0,
|
|
6302
|
-
dataHome: (0,
|
|
6303
|
-
stateHome: (0,
|
|
6389
|
+
configHome: (0, import_node_path13.join)(root, "engine-config"),
|
|
6390
|
+
dataHome: (0, import_node_path13.join)(root, "engine-data"),
|
|
6391
|
+
stateHome: (0, import_node_path13.join)(root, "engine-state")
|
|
6304
6392
|
};
|
|
6305
6393
|
}
|
|
6306
6394
|
async function resolveTheme() {
|
|
@@ -6319,24 +6407,24 @@ async function resolveTheme() {
|
|
|
6319
6407
|
}
|
|
6320
6408
|
async function writeEngineSession(session, catalog, localProviders = {}, framework = "unknown", skillsInstruction = null) {
|
|
6321
6409
|
const xdg = engineXdg();
|
|
6322
|
-
const configDir2 = (0,
|
|
6323
|
-
const dataDir = (0,
|
|
6324
|
-
const themesDir = (0,
|
|
6325
|
-
const pluginsDir = (0,
|
|
6326
|
-
const commandsDir = (0,
|
|
6327
|
-
for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0,
|
|
6328
|
-
(0,
|
|
6410
|
+
const configDir2 = (0, import_node_path13.join)(xdg.configHome, "opencode");
|
|
6411
|
+
const dataDir = (0, import_node_path13.join)(xdg.dataHome, "opencode");
|
|
6412
|
+
const themesDir = (0, import_node_path13.join)(configDir2, "themes");
|
|
6413
|
+
const pluginsDir = (0, import_node_path13.join)(configDir2, "plugins");
|
|
6414
|
+
const commandsDir = (0, import_node_path13.join)(configDir2, "commands");
|
|
6415
|
+
for (const dir of [themesDir, pluginsDir, commandsDir, dataDir, (0, import_node_path13.join)(xdg.stateHome, "opencode")]) {
|
|
6416
|
+
(0, import_node_fs11.mkdirSync)(dir, { recursive: true });
|
|
6329
6417
|
}
|
|
6330
6418
|
const imagegenAvailable = installEngineTools(configDir2) && session.img_on !== false;
|
|
6331
|
-
const cloudInstructionsPath = (0,
|
|
6332
|
-
(0,
|
|
6333
|
-
const skillsPath = (0,
|
|
6419
|
+
const cloudInstructionsPath = (0, import_node_path13.join)(configDir2, CLOUD_INSTRUCTIONS_FILENAME);
|
|
6420
|
+
(0, import_node_fs11.writeFileSync)(cloudInstructionsPath, renderCloudInstructions(framework));
|
|
6421
|
+
const skillsPath = (0, import_node_path13.join)(configDir2, "AGENTFUL_SKILLS.md");
|
|
6334
6422
|
const instructionPaths = [cloudInstructionsPath];
|
|
6335
6423
|
if (skillsInstruction) {
|
|
6336
|
-
(0,
|
|
6424
|
+
(0, import_node_fs11.writeFileSync)(skillsPath, skillsInstruction);
|
|
6337
6425
|
instructionPaths.push(skillsPath);
|
|
6338
6426
|
} else {
|
|
6339
|
-
(0,
|
|
6427
|
+
(0, import_node_fs11.rmSync)(skillsPath, { force: true });
|
|
6340
6428
|
}
|
|
6341
6429
|
const config = buildEngineConfig({
|
|
6342
6430
|
session,
|
|
@@ -6345,24 +6433,24 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
6345
6433
|
imagegenAvailable,
|
|
6346
6434
|
instructionPaths
|
|
6347
6435
|
});
|
|
6348
|
-
(0,
|
|
6349
|
-
(0,
|
|
6436
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path13.join)(configDir2, "config.json"), JSON.stringify(config, null, 2));
|
|
6437
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path13.join)(dataDir, "auth.json"), JSON.stringify({
|
|
6350
6438
|
[PROVIDER_ID]: { apiKey: session.token }
|
|
6351
6439
|
}, null, 2));
|
|
6352
6440
|
const { brandingPluginSource: brandingPluginSource2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
|
|
6353
|
-
const pluginPath = (0,
|
|
6354
|
-
(0,
|
|
6355
|
-
(0,
|
|
6441
|
+
const pluginPath = (0, import_node_path13.join)(pluginsDir, "agentful-branding.tsx");
|
|
6442
|
+
(0, import_node_fs11.writeFileSync)(pluginPath, brandingPluginSource2());
|
|
6443
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path13.join)(configDir2, "tui.json"), JSON.stringify({
|
|
6356
6444
|
theme: "agentful",
|
|
6357
6445
|
plugin: [`file://${pluginPath}`]
|
|
6358
6446
|
}, null, 2));
|
|
6359
|
-
(0,
|
|
6447
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path13.join)(themesDir, "agentful.json"), JSON.stringify(await resolveTheme(), null, 2));
|
|
6360
6448
|
for (const name of Object.keys(SLASH_COMMANDS)) {
|
|
6361
|
-
(0,
|
|
6449
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path13.join)(commandsDir, `${name}.md`), commandMarkdown(name));
|
|
6362
6450
|
}
|
|
6363
6451
|
for (const legacy of ["xdg-config", "xdg-data", "xdg-state"]) {
|
|
6364
6452
|
try {
|
|
6365
|
-
(0,
|
|
6453
|
+
(0, import_node_fs11.rmSync)((0, import_node_path13.join)((0, import_node_os5.homedir)(), ".local", "share", "agentful", legacy), { recursive: true, force: true });
|
|
6366
6454
|
} catch {
|
|
6367
6455
|
}
|
|
6368
6456
|
}
|
|
@@ -6370,8 +6458,8 @@ async function writeEngineSession(session, catalog, localProviders = {}, framewo
|
|
|
6370
6458
|
}
|
|
6371
6459
|
|
|
6372
6460
|
// src/lib/skills.ts
|
|
6373
|
-
var
|
|
6374
|
-
var
|
|
6461
|
+
var import_node_fs12 = require("fs");
|
|
6462
|
+
var import_node_path14 = require("path");
|
|
6375
6463
|
|
|
6376
6464
|
// src/generated/skills.json
|
|
6377
6465
|
var skills_default = {
|
|
@@ -6398,7 +6486,7 @@ var SCAFFOLD_BY_FRAMEWORK = {
|
|
|
6398
6486
|
};
|
|
6399
6487
|
function hasVueDependency(rootDir) {
|
|
6400
6488
|
try {
|
|
6401
|
-
const pkg = JSON.parse((0,
|
|
6489
|
+
const pkg = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path14.join)(rootDir, "package.json"), "utf8"));
|
|
6402
6490
|
return Boolean({ ...pkg.dependencies, ...pkg.devDependencies }["vue"]);
|
|
6403
6491
|
} catch {
|
|
6404
6492
|
return false;
|
|
@@ -6426,7 +6514,7 @@ function renderSkillsInstruction(names) {
|
|
|
6426
6514
|
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";
|
|
6427
6515
|
}
|
|
6428
6516
|
function skillsInstructionFor(framework, rootDir) {
|
|
6429
|
-
if (!(0,
|
|
6517
|
+
if (!(0, import_node_fs12.existsSync)(rootDir)) return null;
|
|
6430
6518
|
return renderSkillsInstruction(selectSkills(framework, rootDir));
|
|
6431
6519
|
}
|
|
6432
6520
|
|
|
@@ -6541,15 +6629,15 @@ function decideLocalProviders(policy) {
|
|
|
6541
6629
|
}
|
|
6542
6630
|
|
|
6543
6631
|
// src/lib/localProviders.ts
|
|
6544
|
-
var
|
|
6545
|
-
var
|
|
6632
|
+
var import_node_fs13 = require("fs");
|
|
6633
|
+
var import_node_path15 = require("path");
|
|
6546
6634
|
var LOCAL_PROVIDERS_FILE = "local-providers.json";
|
|
6547
6635
|
function localProvidersPath() {
|
|
6548
|
-
return (0,
|
|
6636
|
+
return (0, import_node_path15.join)(configDir(), LOCAL_PROVIDERS_FILE);
|
|
6549
6637
|
}
|
|
6550
6638
|
function readLocalProviders() {
|
|
6551
6639
|
try {
|
|
6552
|
-
const raw = JSON.parse((0,
|
|
6640
|
+
const raw = JSON.parse((0, import_node_fs13.readFileSync)(localProvidersPath(), "utf8"));
|
|
6553
6641
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
6554
6642
|
const map = raw.providers && typeof raw.providers === "object" ? raw.providers : raw;
|
|
6555
6643
|
const usable = {};
|
|
@@ -6584,8 +6672,8 @@ function resolveLocalProviders(policy) {
|
|
|
6584
6672
|
}
|
|
6585
6673
|
function writeLocalProvidersExample() {
|
|
6586
6674
|
const path = localProvidersPath();
|
|
6587
|
-
if ((0,
|
|
6588
|
-
(0,
|
|
6675
|
+
if ((0, import_node_fs13.existsSync)(path)) return path;
|
|
6676
|
+
(0, import_node_fs13.mkdirSync)(configDir(), { recursive: true });
|
|
6589
6677
|
const example = {
|
|
6590
6678
|
_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.',
|
|
6591
6679
|
_anthropic: {
|
|
@@ -6595,21 +6683,21 @@ function writeLocalProvidersExample() {
|
|
|
6595
6683
|
models: { "claude-sonnet-4-5": { name: "Claude Sonnet 4.5 (my key)" } }
|
|
6596
6684
|
}
|
|
6597
6685
|
};
|
|
6598
|
-
(0,
|
|
6686
|
+
(0, import_node_fs13.writeFileSync)(path, JSON.stringify(example, null, 2) + "\n", "utf8");
|
|
6599
6687
|
try {
|
|
6600
|
-
(0,
|
|
6688
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
6601
6689
|
} catch {
|
|
6602
6690
|
}
|
|
6603
6691
|
return path;
|
|
6604
6692
|
}
|
|
6605
6693
|
|
|
6606
6694
|
// src/lib/sessions.ts
|
|
6607
|
-
var
|
|
6608
|
-
var
|
|
6695
|
+
var import_node_fs14 = require("fs");
|
|
6696
|
+
var import_node_path16 = require("path");
|
|
6609
6697
|
var import_node_child_process4 = require("child_process");
|
|
6610
6698
|
function lastSessionForDirectory(cwd = process.cwd()) {
|
|
6611
|
-
const dbPath = (0,
|
|
6612
|
-
if (!(0,
|
|
6699
|
+
const dbPath = (0, import_node_path16.join)(engineXdg().dataHome, "opencode", "opencode.db");
|
|
6700
|
+
if (!(0, import_node_fs14.existsSync)(dbPath)) return null;
|
|
6613
6701
|
const escaped = cwd.replace(/'/g, "''");
|
|
6614
6702
|
const res = (0, import_node_child_process4.spawnSync)(
|
|
6615
6703
|
"sqlite3",
|
|
@@ -6688,7 +6776,7 @@ async function tuiCommand(opts = {}) {
|
|
|
6688
6776
|
}
|
|
6689
6777
|
console.log("");
|
|
6690
6778
|
if (process.stdout.isTTY) process.stdout.write(`\x1B]0;${brand.displayName}\x07`);
|
|
6691
|
-
const code = await new Promise((
|
|
6779
|
+
const code = await new Promise((resolve2) => {
|
|
6692
6780
|
const engineArgs = opts.session ? ["--session", opts.session] : [];
|
|
6693
6781
|
const child = (0, import_node_child_process5.spawn)(binPath, engineArgs, {
|
|
6694
6782
|
stdio: "inherit",
|
|
@@ -6697,7 +6785,7 @@ async function tuiCommand(opts = {}) {
|
|
|
6697
6785
|
...process.env,
|
|
6698
6786
|
// Slash commands run `agentful …` through the agent's bash tool, which
|
|
6699
6787
|
// has no access to the user's shell aliases.
|
|
6700
|
-
PATH: `${binDir}${
|
|
6788
|
+
PATH: `${binDir}${import_node_path17.delimiter}${process.env.PATH || ""}`,
|
|
6701
6789
|
XDG_CONFIG_HOME: xdg.configHome,
|
|
6702
6790
|
XDG_DATA_HOME: xdg.dataHome,
|
|
6703
6791
|
XDG_STATE_HOME: xdg.stateHome,
|
|
@@ -6715,10 +6803,10 @@ async function tuiCommand(opts = {}) {
|
|
|
6715
6803
|
...session.image_model ? { IMAGE_MODEL: session.image_model } : {}
|
|
6716
6804
|
}
|
|
6717
6805
|
});
|
|
6718
|
-
child.on("exit", (c) =>
|
|
6806
|
+
child.on("exit", (c) => resolve2(c ?? 0));
|
|
6719
6807
|
child.on("error", (err2) => {
|
|
6720
6808
|
ui.fail(`Could not start the engine: ${err2.message}`);
|
|
6721
|
-
|
|
6809
|
+
resolve2(1);
|
|
6722
6810
|
});
|
|
6723
6811
|
});
|
|
6724
6812
|
try {
|
|
@@ -6802,28 +6890,28 @@ async function shareCommand(opts) {
|
|
|
6802
6890
|
}
|
|
6803
6891
|
|
|
6804
6892
|
// src/commands/pull.ts
|
|
6805
|
-
var
|
|
6806
|
-
var
|
|
6893
|
+
var import_node_fs15 = require("fs");
|
|
6894
|
+
var import_node_path18 = require("path");
|
|
6807
6895
|
init_branding();
|
|
6808
6896
|
init_branding();
|
|
6809
6897
|
function isProbablyBase64Binary(path) {
|
|
6810
6898
|
return /\.(png|jpe?g|gif|webp|ico|woff2?|ttf|otf|eot|pdf|zip|mp[34]|webm|avif)$/i.test(path);
|
|
6811
6899
|
}
|
|
6812
6900
|
function writeEntry(root, rel, value) {
|
|
6813
|
-
const target = (0,
|
|
6814
|
-
(0,
|
|
6901
|
+
const target = (0, import_node_path18.join)(root, rel);
|
|
6902
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path18.dirname)(target), { recursive: true });
|
|
6815
6903
|
const content = typeof value === "object" && value !== null && "content" in value ? String(value.content) : String(value ?? "");
|
|
6816
6904
|
if (isProbablyBase64Binary(rel)) {
|
|
6817
|
-
(0,
|
|
6905
|
+
(0, import_node_fs15.writeFileSync)(target, Buffer.from(content, "base64"));
|
|
6818
6906
|
} else {
|
|
6819
|
-
(0,
|
|
6907
|
+
(0, import_node_fs15.writeFileSync)(target, content, "utf8");
|
|
6820
6908
|
}
|
|
6821
6909
|
}
|
|
6822
6910
|
async function pullCommand(opts) {
|
|
6823
6911
|
console.log(banner());
|
|
6824
6912
|
const auth = await ensureAuth();
|
|
6825
6913
|
const project = requireProject();
|
|
6826
|
-
const nonHidden = (0,
|
|
6914
|
+
const nonHidden = (0, import_node_fs15.readdirSync)(process.cwd()).filter((n) => n !== ".agentful" && !n.startsWith("."));
|
|
6827
6915
|
if (nonHidden.length > 0 && !opts.force) {
|
|
6828
6916
|
throw new ApiError(
|
|
6829
6917
|
0,
|
|
@@ -6847,9 +6935,9 @@ async function pullCommand(opts) {
|
|
|
6847
6935
|
ui.warn(`Skipped ${rel} (HTTP ${resp.status})`);
|
|
6848
6936
|
continue;
|
|
6849
6937
|
}
|
|
6850
|
-
const target = (0,
|
|
6851
|
-
(0,
|
|
6852
|
-
(0,
|
|
6938
|
+
const target = (0, import_node_path18.join)(process.cwd(), rel);
|
|
6939
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path18.dirname)(target), { recursive: true });
|
|
6940
|
+
(0, import_node_fs15.writeFileSync)(target, Buffer.from(await resp.arrayBuffer()));
|
|
6853
6941
|
written++;
|
|
6854
6942
|
}
|
|
6855
6943
|
} else if (data.files) {
|
|
@@ -6992,9 +7080,10 @@ program2.name("agentful").description("Agentful in your terminal \u2014 local de
|
|
|
6992
7080
|
program2.command("login").description("Sign in to your Agentful account (device flow)").option("--no-browser", "do not open the browser automatically").action(run((opts) => loginCommand({ browser: opts.browser !== false })));
|
|
6993
7081
|
program2.command("logout").description("Remove the stored credentials").action(run(logoutCommand));
|
|
6994
7082
|
program2.command("whoami").description("Show the signed-in account").action(run(whoamiCommand));
|
|
6995
|
-
program2.command("init").description("Create (or link) the Agentful cloud project for this directory").option("--link <projectId>", "link an existing project instead of creating one").option("--title <title>", "project title (skips the prompt)").option("--template <framework>", "scaffold
|
|
7083
|
+
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)));
|
|
6996
7084
|
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)));
|
|
6997
7085
|
program2.command("build-status").description("Show the cloud's record of the last build (the real error on failures)").action(run(buildStatusCommand));
|
|
7086
|
+
program2.command("backend").description("Open this project's Backend tab (managed DB + server actions) in the browser").action(run(backendCommand));
|
|
6998
7087
|
program2.command("open").description("Open the live preview in the browser").action(run(openCommand));
|
|
6999
7088
|
program2.command("tui").description("Start the Agentful coding TUI with your Agentful account").option("-s, --session <id>", "resume a previous session").action(run((opts) => tuiCommand(opts)));
|
|
7000
7089
|
program2.command("publish <subdomain>").description("Publish the built project at https://<subdomain>.agentful.dev").action(run(publishCommand));
|