agentful 0.4.15 → 0.4.17
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 +13 -7
- package/dist/index.cjs +298 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,18 +44,24 @@ Inside the interface, `/` lists the Agentful commands (`/setup`, `/push`,
|
|
|
44
44
|
site, and asks you before it changes a file or pushes.
|
|
45
45
|
|
|
46
46
|
`push` respects your `.gitignore` and always excludes `.git`, `node_modules`,
|
|
47
|
-
build output and every `.env` file. A push carries at most
|
|
48
|
-
|
|
49
|
-
an `index.html` at its top level.
|
|
47
|
+
build output and every `.env` file. A push carries at most 25 MiB of files
|
|
48
|
+
(32 MiB compressed) and 2,000 files, and a static site or a prebuilt upload needs
|
|
49
|
+
an `index.html` at its top level. The preview does not deliver every file yet:
|
|
50
|
+
images, fonts and PDFs up to about 4.4 MiB each, pages and scripts up to about
|
|
51
|
+
5.5 MiB, and no video or audio. `push` names the files this concerns and uploads
|
|
52
|
+
them all the same. `push` checks all of this before it signs you
|
|
50
53
|
in or creates a project.
|
|
51
54
|
|
|
52
55
|
`agentful push --dry-run` shows that check on its own: what would be uploaded
|
|
53
56
|
and what is left out, the largest files, identical copies, media embedded in
|
|
54
|
-
HTML, and every reason the upload would be rejected.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
HTML, and every reason the upload would be rejected. A file that is larger
|
|
58
|
+
than a whole push on its own is named as such: it cannot be uploaded at all,
|
|
59
|
+
whatever else is left out. It uploads nothing, creates no project and changes
|
|
60
|
+
no file; it exits with 1 when the push would be blocked. `--dry-run --json`
|
|
61
|
+
prints the same analysis as one JSON document
|
|
57
62
|
(`"schema": "agentful.push-analysis"`) for scripts and agents; with `--summary`
|
|
58
|
-
it leaves out the list of every file
|
|
63
|
+
it leaves out the list of every file, keeps totals, limits and findings, and
|
|
64
|
+
prints every size as text next to its byte count.
|
|
59
65
|
|
|
60
66
|
## What you can deploy
|
|
61
67
|
|
package/dist/index.cjs
CHANGED
|
@@ -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.17" ? "0.4.17" : null.version;
|
|
3048
3048
|
brand = {
|
|
3049
3049
|
name: "agentful",
|
|
3050
3050
|
// the command users type
|
|
@@ -5780,17 +5780,49 @@ var contract_default = {
|
|
|
5780
5780
|
|
|
5781
5781
|
// src/lib/uploadLimits.ts
|
|
5782
5782
|
var MAX_ZIP_UPLOAD_BYTES = contract_default.limits.max_zip_upload_bytes;
|
|
5783
|
+
var MAX_DIRECT_ZIP_UPLOAD_BYTES = 32 * 1024 * 1024;
|
|
5783
5784
|
var MAX_UNPACKED_BYTES = 25 * 1024 * 1024;
|
|
5784
5785
|
var MAX_UPLOAD_FILES = 2e3;
|
|
5785
5786
|
var MAX_INLINE_REQUEST_BYTES = 6 * 1024 * 1024 - 64 * 1024;
|
|
5786
5787
|
function uploadRequestBody(zipBase64, mode, declaration) {
|
|
5787
5788
|
return { zip_base64: zipBase64, mode, clean: true, ...declaration ? { backend_declaration: declaration } : {} };
|
|
5788
5789
|
}
|
|
5789
|
-
function
|
|
5790
|
+
function maxInlineZipBytes(mode = "source", declaration = null) {
|
|
5790
5791
|
const around = Buffer.byteLength(JSON.stringify(uploadRequestBody("", mode, declaration)), "utf8");
|
|
5791
5792
|
const base64Budget = Math.max(0, MAX_INLINE_REQUEST_BYTES - around);
|
|
5792
5793
|
return Math.min(MAX_ZIP_UPLOAD_BYTES, Math.floor(base64Budget / 4) * 3);
|
|
5793
5794
|
}
|
|
5795
|
+
function maxZipBytesForUpload() {
|
|
5796
|
+
return MAX_DIRECT_ZIP_UPLOAD_BYTES;
|
|
5797
|
+
}
|
|
5798
|
+
function announceRequestBody(zipBytes, sha256Hex, mode) {
|
|
5799
|
+
return { upload: { size: zipBytes, sha256: sha256Hex }, mode };
|
|
5800
|
+
}
|
|
5801
|
+
function completeRequestBody(uploadId, mode, declaration) {
|
|
5802
|
+
return { upload_id: uploadId, mode, clean: true, ...declaration ? { backend_declaration: declaration } : {} };
|
|
5803
|
+
}
|
|
5804
|
+
var PREVIEW_BINARY_MEASURED_PASS_BYTES = 4666163;
|
|
5805
|
+
var PREVIEW_MAX_BINARY_BYTES = PREVIEW_BINARY_MEASURED_PASS_BYTES;
|
|
5806
|
+
var PREVIEW_MAX_TEXT_BYTES = 5.5 * 1024 * 1024;
|
|
5807
|
+
var PREVIEW_BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5808
|
+
"avif",
|
|
5809
|
+
"apng",
|
|
5810
|
+
"webp",
|
|
5811
|
+
"png",
|
|
5812
|
+
"jpg",
|
|
5813
|
+
"jpeg",
|
|
5814
|
+
"gif",
|
|
5815
|
+
"svg",
|
|
5816
|
+
"ico",
|
|
5817
|
+
"bmp",
|
|
5818
|
+
"tiff",
|
|
5819
|
+
"woff",
|
|
5820
|
+
"woff2",
|
|
5821
|
+
"ttf",
|
|
5822
|
+
"otf",
|
|
5823
|
+
"eot",
|
|
5824
|
+
"pdf"
|
|
5825
|
+
]);
|
|
5794
5826
|
var SERVER_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
5795
5827
|
"node_modules",
|
|
5796
5828
|
".git",
|
|
@@ -5954,7 +5986,7 @@ function scanTree(rootDir, mode) {
|
|
|
5954
5986
|
function collectFiles(rootDir, mode) {
|
|
5955
5987
|
return scanTree(rootDir, mode).files;
|
|
5956
5988
|
}
|
|
5957
|
-
function
|
|
5989
|
+
function zipFiles(files, maxBytes = maxZipBytesForUpload()) {
|
|
5958
5990
|
if (files.length === 0) {
|
|
5959
5991
|
throw new ApiError(0, "empty_project", "Nothing to push \u2014 no files found after applying ignore rules.");
|
|
5960
5992
|
}
|
|
@@ -5970,11 +6002,7 @@ function zipToBase64(files, maxBytes = maxZipBytesForUpload()) {
|
|
|
5970
6002
|
`The upload is ${zipped.byteLength.toLocaleString("en-US")} bytes compressed \u2014 a push carries at most ${maxBytes.toLocaleString("en-US")}. \`agentful push --dry-run\` shows what takes the space.`
|
|
5971
6003
|
);
|
|
5972
6004
|
}
|
|
5973
|
-
return {
|
|
5974
|
-
base64: Buffer.from(zipped).toString("base64"),
|
|
5975
|
-
bytes: zipped.byteLength,
|
|
5976
|
-
count: files.length
|
|
5977
|
-
};
|
|
6005
|
+
return { data: zipped, bytes: zipped.byteLength, count: files.length };
|
|
5978
6006
|
}
|
|
5979
6007
|
function detectDistDir(rootDir, override) {
|
|
5980
6008
|
if (override) {
|
|
@@ -6500,6 +6528,16 @@ var CLASS_BY_EXTENSION = new Map(
|
|
|
6500
6528
|
);
|
|
6501
6529
|
var EMBEDDED_SCAN_CLASSES = /* @__PURE__ */ new Set(["html", "css", "script", "data"]);
|
|
6502
6530
|
var baseName = (rel) => rel.slice(rel.lastIndexOf("/") + 1);
|
|
6531
|
+
var TEXT_CLASSES = /* @__PURE__ */ new Set(["html", "css", "script", "data"]);
|
|
6532
|
+
var UNDELIVERED_CLASSES = /* @__PURE__ */ new Set(["image", "font", "document", "video", "audio", "archive"]);
|
|
6533
|
+
function previewDelivery(rel, bytes2) {
|
|
6534
|
+
const base = baseName(rel);
|
|
6535
|
+
const ext = base.includes(".") ? base.slice(base.lastIndexOf(".") + 1).toLowerCase() : "";
|
|
6536
|
+
if (PREVIEW_BINARY_EXTENSIONS.has(ext)) return bytes2 > PREVIEW_MAX_BINARY_BYTES ? "too_large" : "ok";
|
|
6537
|
+
const cls = classOf(rel);
|
|
6538
|
+
if (TEXT_CLASSES.has(cls)) return bytes2 > PREVIEW_MAX_TEXT_BYTES ? "too_large" : "ok";
|
|
6539
|
+
return UNDELIVERED_CLASSES.has(cls) || ext === "wasm" ? "not_delivered" : "ok";
|
|
6540
|
+
}
|
|
6503
6541
|
function classOf(rel) {
|
|
6504
6542
|
const base = baseName(rel);
|
|
6505
6543
|
const dot = base.lastIndexOf(".");
|
|
@@ -6561,7 +6599,7 @@ function formatBytes(bytes2, rounding = "nearest") {
|
|
|
6561
6599
|
}
|
|
6562
6600
|
if (unit === 0 || Number.isInteger(value)) return `${value} ${units[unit]}`;
|
|
6563
6601
|
const tenths = value * 10;
|
|
6564
|
-
const rounded = (rounding === "down" ? Math.floor(tenths) : Math.round(tenths)) / 10;
|
|
6602
|
+
const rounded = (rounding === "down" ? Math.floor(tenths) : rounding === "up" ? Math.ceil(tenths) : Math.round(tenths)) / 10;
|
|
6565
6603
|
return `${rounded.toFixed(1)} ${units[unit]}`;
|
|
6566
6604
|
}
|
|
6567
6605
|
function sizeOverLimit(bytes2, limit) {
|
|
@@ -6612,7 +6650,7 @@ function failedAnalysis(mode, projectDir, blocker) {
|
|
|
6612
6650
|
ok: false,
|
|
6613
6651
|
framework: null,
|
|
6614
6652
|
project: projectLink(projectDir),
|
|
6615
|
-
limits: limits(maxZipBytesForUpload(
|
|
6653
|
+
limits: limits(maxZipBytesForUpload()),
|
|
6616
6654
|
totals: {
|
|
6617
6655
|
files: 0,
|
|
6618
6656
|
bytes: 0,
|
|
@@ -6728,6 +6766,14 @@ function analyzePush(options) {
|
|
|
6728
6766
|
}
|
|
6729
6767
|
duplicates.sort((a, b) => b.redundant_zip_bytes - a.redundant_zip_bytes || (a.paths[0] < b.paths[0] ? -1 : 1));
|
|
6730
6768
|
const redundantZipBytes = duplicates.reduce((total, group) => total + group.redundant_zip_bytes, 0);
|
|
6769
|
+
const maxZipBytes = maxZipBytesForUpload();
|
|
6770
|
+
const tooBigAsFile = (file) => view.stored.has(file.path) && file.bytes > MAX_UNPACKED_BYTES;
|
|
6771
|
+
const tooBigInZip = (file) => file.zipLower > maxZipBytes;
|
|
6772
|
+
const oversized = measured.filter((file) => tooBigAsFile(file) || tooBigInZip(file)).sort((a, b) => b.bytes - a.bytes || byPath(a, b));
|
|
6773
|
+
const oversizedPaths = new Set(oversized.map((file) => file.path));
|
|
6774
|
+
const oversizedAsFile = oversized.filter(tooBigAsFile);
|
|
6775
|
+
const restZipLower = zipLower - oversized.reduce((total, file) => total + file.zipLower, 0);
|
|
6776
|
+
const restStoredBytes = storedBytes - oversizedAsFile.reduce((total, file) => total + file.bytes, 0);
|
|
6731
6777
|
const preflight = mode === "source" ? runPreflight(rootDir) : null;
|
|
6732
6778
|
const framework = preflight?.framework ?? null;
|
|
6733
6779
|
const hasManifest = storedNames.has("package.json");
|
|
@@ -6739,12 +6785,14 @@ function analyzePush(options) {
|
|
|
6739
6785
|
return {
|
|
6740
6786
|
path: file.path,
|
|
6741
6787
|
bytes: file.bytes,
|
|
6788
|
+
zip_bytes: file.zip_bytes,
|
|
6742
6789
|
title: file.title,
|
|
6743
6790
|
sha256: file.sha256,
|
|
6744
|
-
same_content_as: first && first !== file.path ? first : null
|
|
6791
|
+
same_content_as: first && first !== file.path ? first : null,
|
|
6792
|
+
...oversizedPaths.has(file.path) ? { larger_than_a_push: true } : {}
|
|
6745
6793
|
};
|
|
6746
6794
|
});
|
|
6747
|
-
const
|
|
6795
|
+
const fittingCandidates = candidates.filter((candidate) => !candidate.larger_than_a_push);
|
|
6748
6796
|
const zipLimit = formatBytes(maxZipBytes, "down");
|
|
6749
6797
|
const blockers = [];
|
|
6750
6798
|
const warnings = [];
|
|
@@ -6772,20 +6820,39 @@ function analyzePush(options) {
|
|
|
6772
6820
|
message: `${plural(measured.length, "file")} \u2014 the platform accepts at most ${MAX_UPLOAD_FILES.toLocaleString("en-US")} files per push.`
|
|
6773
6821
|
});
|
|
6774
6822
|
}
|
|
6775
|
-
|
|
6823
|
+
const largerOnTheirOwn = (files, sizeOf, limit) => {
|
|
6824
|
+
const named = samplePaths(files.map((file) => `${file.path} (${sizeOverLimit(sizeOf(file), limit)[0]})`));
|
|
6825
|
+
return files.length === 1 ? ` ${named} is larger than that on its own, so no push can carry it.` : ` ${plural(files.length, "file")} are each larger than that on their own, so no push can carry them: ${named}.`;
|
|
6826
|
+
};
|
|
6827
|
+
const filesTooLarge = storedBytes > MAX_UNPACKED_BYTES;
|
|
6828
|
+
if (filesTooLarge) {
|
|
6776
6829
|
const [size, allowed] = sizeOverLimit(storedBytes, MAX_UNPACKED_BYTES);
|
|
6830
|
+
let message = `The files add up to ${size} \u2014 the platform accepts at most ${allowed} of files per push.`;
|
|
6831
|
+
if (oversizedAsFile.length > 0) {
|
|
6832
|
+
message += largerOnTheirOwn(oversizedAsFile, (file) => file.bytes, MAX_UNPACKED_BYTES);
|
|
6833
|
+
message += ` Without ${oversizedAsFile.length === 1 ? "it" : "them"} the files ${restStoredBytes > MAX_UNPACKED_BYTES ? `still add up to ${sizeOverLimit(restStoredBytes, MAX_UNPACKED_BYTES)[0]}` : `add up to ${formatBytes(restStoredBytes)}, which is within that limit`}.`;
|
|
6834
|
+
}
|
|
6777
6835
|
blockers.push({
|
|
6778
6836
|
code: "unpacked_too_large",
|
|
6779
6837
|
overridable: false,
|
|
6780
|
-
message
|
|
6838
|
+
message,
|
|
6839
|
+
...oversizedAsFile.length > 0 ? { paths: oversizedAsFile.map((file) => file.path).slice(0, FINDING_PATHS) } : {}
|
|
6781
6840
|
});
|
|
6782
6841
|
}
|
|
6783
6842
|
if (zipLower > maxZipBytes) {
|
|
6784
6843
|
const [size, allowed] = sizeOverLimit(zipExact ? zipBytes : zipLower, maxZipBytes);
|
|
6844
|
+
let message = `The upload is ${zipExact ? "" : "at least "}${size} compressed \u2014 a push carries at most ${allowed} compressed.`;
|
|
6845
|
+
const namedHere = oversized.filter((file) => tooBigInZip(file) && !(filesTooLarge && tooBigAsFile(file)));
|
|
6846
|
+
if (namedHere.length > 0) message += largerOnTheirOwn(namedHere, (file) => file.zipLower, maxZipBytes);
|
|
6847
|
+
if (oversized.length > 0) {
|
|
6848
|
+
const without = namedHere.length < oversized.length ? "the files no push can carry" : namedHere.length === 1 ? "it" : "them";
|
|
6849
|
+
message += ` Without ${without} the upload is ${restZipLower > maxZipBytes ? `still ${sizeOverLimit(restZipLower, maxZipBytes)[0]} compressed` : `${formatBytes(restZipLower)} compressed, which is within that limit`}.`;
|
|
6850
|
+
}
|
|
6785
6851
|
blockers.push({
|
|
6786
6852
|
code: "zip_too_large",
|
|
6787
6853
|
overridable: false,
|
|
6788
|
-
message
|
|
6854
|
+
message,
|
|
6855
|
+
...namedHere.length > 0 ? { paths: namedHere.map((file) => file.path).slice(0, FINDING_PATHS) } : {}
|
|
6789
6856
|
});
|
|
6790
6857
|
} else if (!zipExact && zipBytes > maxZipBytes) {
|
|
6791
6858
|
warnings.push({
|
|
@@ -6794,10 +6861,12 @@ function analyzePush(options) {
|
|
|
6794
6861
|
});
|
|
6795
6862
|
}
|
|
6796
6863
|
if (entryMissing) {
|
|
6864
|
+
const tooBig = candidates.filter((candidate) => candidate.larger_than_a_push);
|
|
6865
|
+
const cannotBecomeIt = tooBig.length === 0 ? "" : fittingCandidates.length === 0 ? candidates.length === 1 ? " The one HTML file here cannot become it as it is: it is larger than a whole push." : ` None of the ${candidates.length} HTML files here can become it as they are: each is larger than a whole push.` : ` ${tooBig.length} of the ${candidates.length} HTML files here cannot become it as ${tooBig.length === 1 ? "it is" : "they are"}, larger than a whole push: ${samplePaths(tooBig.map((candidate) => candidate.path))}.`;
|
|
6797
6866
|
blockers.push({
|
|
6798
6867
|
code: "entry_missing",
|
|
6799
6868
|
overridable: false,
|
|
6800
|
-
message: mode === "dist" ? `No index.html at the top level of ${dirLabel === "." ? "the uploaded folder" : `${dirLabel}/`}. A prebuilt upload is served as it is, and index.html is its start page.` : "No index.html at the top level. Without a package.json this is a static site, and the platform serves index.html as its start page."
|
|
6869
|
+
message: (mode === "dist" ? `No index.html at the top level of ${dirLabel === "." ? "the uploaded folder" : `${dirLabel}/`}. A prebuilt upload is served as it is, and index.html is its start page.` : "No index.html at the top level. Without a package.json this is a static site, and the platform serves index.html as its start page.") + cannotBecomeIt
|
|
6801
6870
|
});
|
|
6802
6871
|
}
|
|
6803
6872
|
const backend = mode === "source" ? checkBackendDeclaration(rootDir) : null;
|
|
@@ -6829,6 +6898,25 @@ function analyzePush(options) {
|
|
|
6829
6898
|
});
|
|
6830
6899
|
}
|
|
6831
6900
|
}
|
|
6901
|
+
const servedAsIs = stored.filter((file) => mode === "dist" || framework === "vanilla" || /^(public|static)\//.test(view.stored.get(file.path) ?? ""));
|
|
6902
|
+
const tooLargeForPreview = servedAsIs.filter((file) => previewDelivery(file.path, file.bytes) === "too_large").sort((a, b) => b.bytes - a.bytes || byPath(a, b));
|
|
6903
|
+
if (tooLargeForPreview.length > 0) {
|
|
6904
|
+
const one = tooLargeForPreview.length === 1;
|
|
6905
|
+
warnings.push({
|
|
6906
|
+
code: "preview_file_too_large",
|
|
6907
|
+
message: `${plural(tooLargeForPreview.length, "file is", "files are")} larger than the preview delivers (about ${formatBytes(PREVIEW_MAX_BINARY_BYTES, "down")} for images, fonts and PDFs, about ${formatBytes(PREVIEW_MAX_TEXT_BYTES, "down")} for pages, scripts and other text): ${samplePaths(tooLargeForPreview.map((file) => `${file.path} (${formatBytes(file.bytes)})`))}. ${one ? "It is" : "They are"} uploaded, but the preview answers with an error instead of the file.`,
|
|
6908
|
+
paths: tooLargeForPreview.map((file) => file.path).slice(0, FINDING_PATHS)
|
|
6909
|
+
});
|
|
6910
|
+
}
|
|
6911
|
+
const notDeliveredByPreview = servedAsIs.filter((file) => previewDelivery(file.path, file.bytes) === "not_delivered").sort(byPath);
|
|
6912
|
+
if (notDeliveredByPreview.length > 0) {
|
|
6913
|
+
const one = notDeliveredByPreview.length === 1;
|
|
6914
|
+
warnings.push({
|
|
6915
|
+
code: "preview_type_not_delivered",
|
|
6916
|
+
message: `${plural(notDeliveredByPreview.length, "file is", "files are")} of a kind the preview does not deliver intact (video, audio, archives and other binary formats): ${samplePaths(notDeliveredByPreview.map((file) => file.path))}. ${one ? "It is" : "They are"} uploaded, but ${one ? "it does" : "they do"} not play or open in the preview.`,
|
|
6917
|
+
paths: notDeliveredByPreview.map((file) => file.path).slice(0, FINDING_PATHS)
|
|
6918
|
+
});
|
|
6919
|
+
}
|
|
6832
6920
|
const filesOmitted = Math.max(0, measured.length - budgets.fileListCap);
|
|
6833
6921
|
if (filesOmitted > 0) {
|
|
6834
6922
|
warnings.push({
|
|
@@ -6838,11 +6926,11 @@ function analyzePush(options) {
|
|
|
6838
6926
|
}
|
|
6839
6927
|
const tooLarge = blockers.some((b) => b.code === "zip_too_large" || b.code === "unpacked_too_large");
|
|
6840
6928
|
if (entryMissing) {
|
|
6841
|
-
if (
|
|
6929
|
+
if (fittingCandidates.length > 0) {
|
|
6842
6930
|
suggestions.push({
|
|
6843
6931
|
code: "name_start_page",
|
|
6844
6932
|
message: "Rename or copy the page that should open first to index.html at the top level, check that its relative links still resolve, then push again.",
|
|
6845
|
-
paths:
|
|
6933
|
+
paths: fittingCandidates.map((candidate) => candidate.path).slice(0, FINDING_PATHS)
|
|
6846
6934
|
});
|
|
6847
6935
|
}
|
|
6848
6936
|
const siteDirs = /* @__PURE__ */ new Set();
|
|
@@ -6864,29 +6952,33 @@ function analyzePush(options) {
|
|
|
6864
6952
|
}
|
|
6865
6953
|
}
|
|
6866
6954
|
if (tooLarge) {
|
|
6867
|
-
const
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6955
|
+
const overZip = zipLower - maxZipBytes;
|
|
6956
|
+
const overFiles = storedBytes - MAX_UNPACKED_BYTES;
|
|
6957
|
+
const mustStayOut = [
|
|
6958
|
+
overZip > 0 ? `${formatBytes(overZip, "up")} of the ${formatBytes(zipLower)} compressed` : "",
|
|
6959
|
+
overFiles > 0 ? `${formatBytes(overFiles, "up")} of the ${formatBytes(storedBytes)} of files` : ""
|
|
6960
|
+
].filter(Boolean);
|
|
6961
|
+
const toFit = ` To fit, at least ${mustStayOut.join(" and ")} ${mustStayOut.length > 1 ? "have" : "has"} to stay out.`;
|
|
6962
|
+
const spareCopies = duplicates.filter((group) => !oversizedPaths.has(group.paths[0]));
|
|
6963
|
+
const extraStored = (group) => group.paths.slice(1).filter((path) => view.stored.has(path)).length * group.bytes;
|
|
6964
|
+
const spare = spareCopies.reduce((total, group) => total + (filesTooLarge ? extraStored(group) : group.redundant_zip_bytes), 0);
|
|
6965
|
+
const base = filesTooLarge ? oversized.length > 0 ? restStoredBytes : storedBytes : oversized.length > 0 ? restZipLower : zipBytes;
|
|
6966
|
+
const limit = filesTooLarge ? MAX_UNPACKED_BYTES : maxZipBytes;
|
|
6967
|
+
if (spareCopies.length > 0 && spare >= base / 20) {
|
|
6968
|
+
const copies = spareCopies.reduce((total, group) => total + group.paths.length - 1, 0);
|
|
6969
|
+
const remaining = base - spare;
|
|
6878
6970
|
suggestions.push({
|
|
6879
6971
|
code: "remove_identical_copies",
|
|
6880
|
-
message: `${plural(copies, "file is an identical copy", "files are identical copies")} of another file and ${copies === 1 ? "adds" : "add"} ${formatBytes(
|
|
6881
|
-
paths:
|
|
6972
|
+
message: `${plural(copies, "file is an identical copy", "files are identical copies")} of another file and ${copies === 1 ? "adds" : "add"} ${formatBytes(spare)} to the ${filesTooLarge ? "files of the upload" : "compressed upload"}. If nothing links to the extra names, one copy each brings ${oversized.length > 0 ? "what is left without the files no push can carry" : "it"} to ${formatBytes(remaining)}${remaining > limit ? ` \u2014 still above the ${formatBytes(limit, "down")} limit` : ""}.`,
|
|
6973
|
+
paths: spareCopies.flatMap((group) => group.paths.slice(1)).slice(0, FINDING_PATHS)
|
|
6882
6974
|
});
|
|
6883
6975
|
}
|
|
6884
6976
|
suggestions.push(mode === "source" ? {
|
|
6885
6977
|
code: "exclude_with_gitignore",
|
|
6886
|
-
message:
|
|
6978
|
+
message: `Files and folders listed in .gitignore are not uploaded. Leave out what the site does not serve \u2014 originals, working files, exports.${toFit}`
|
|
6887
6979
|
} : {
|
|
6888
6980
|
code: "narrow_prebuilt_directory",
|
|
6889
|
-
message:
|
|
6981
|
+
message: `A prebuilt upload takes every file in the folder. Put the finished site into a folder of its own and pass it with --dir.${toFit}`
|
|
6890
6982
|
});
|
|
6891
6983
|
suggestions.push({
|
|
6892
6984
|
code: "upload_limit",
|
|
@@ -6961,7 +7053,19 @@ var SUMMARY_LISTS = {
|
|
|
6961
7053
|
finding_paths: 8
|
|
6962
7054
|
};
|
|
6963
7055
|
var SUMMARY_MAX_BYTES = 24 * 1024;
|
|
6964
|
-
var
|
|
7056
|
+
var sizeLabelKey = (key) => key === "base64_chars" ? "base64_size" : /(^|_)bytes(_|$)/.test(key) ? key.replace("bytes", "size") : null;
|
|
7057
|
+
function withSizeLabels(value) {
|
|
7058
|
+
if (Array.isArray(value)) return value.map(withSizeLabels);
|
|
7059
|
+
if (!value || typeof value !== "object") return value;
|
|
7060
|
+
const labelled = {};
|
|
7061
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
7062
|
+
labelled[key] = withSizeLabels(inner);
|
|
7063
|
+
const label = typeof inner === "number" ? sizeLabelKey(key) : null;
|
|
7064
|
+
if (label) labelled[label] = formatBytes(inner, key.startsWith("max_") ? "down" : "nearest");
|
|
7065
|
+
}
|
|
7066
|
+
return labelled;
|
|
7067
|
+
}
|
|
7068
|
+
var printAnalysis = (analysis) => `${JSON.stringify(analysis.view === "summary" ? withSizeLabels(analysis) : analysis, null, 2)}
|
|
6965
7069
|
`;
|
|
6966
7070
|
function summarize(analysis, divisor) {
|
|
6967
7071
|
const shortened = {};
|
|
@@ -7028,6 +7132,103 @@ function wouldUpload(analysis, force = false) {
|
|
|
7028
7132
|
return analysis.blockers.every((blocker) => blocker.overridable && force);
|
|
7029
7133
|
}
|
|
7030
7134
|
|
|
7135
|
+
// src/lib/zipTransfer.ts
|
|
7136
|
+
var import_node_crypto2 = require("crypto");
|
|
7137
|
+
var INLINE_UPLOAD_TIMEOUT_MS = 12e4;
|
|
7138
|
+
var ANNOUNCE_TIMEOUT_MS = 3e4;
|
|
7139
|
+
var PUT_TIMEOUT_MS = 6e5;
|
|
7140
|
+
var COMPLETE_TIMEOUT_MS = 12e4;
|
|
7141
|
+
var PUT_ATTEMPTS = 2;
|
|
7142
|
+
async function uploadZip(upload, deps = { request, fetch }) {
|
|
7143
|
+
const { route, token, zip, mode, declaration, retry } = upload;
|
|
7144
|
+
if (zip.byteLength <= maxInlineZipBytes(mode, declaration)) {
|
|
7145
|
+
return deps.request(route, {
|
|
7146
|
+
token,
|
|
7147
|
+
retry,
|
|
7148
|
+
timeoutMs: INLINE_UPLOAD_TIMEOUT_MS,
|
|
7149
|
+
body: uploadRequestBody(Buffer.from(zip).toString("base64"), mode, declaration)
|
|
7150
|
+
});
|
|
7151
|
+
}
|
|
7152
|
+
const ticket = await announce(upload, deps);
|
|
7153
|
+
await putZip(ticket, zip, deps);
|
|
7154
|
+
return deps.request(route, {
|
|
7155
|
+
token,
|
|
7156
|
+
retry,
|
|
7157
|
+
timeoutMs: COMPLETE_TIMEOUT_MS,
|
|
7158
|
+
body: completeRequestBody(ticket.upload_id, mode, declaration)
|
|
7159
|
+
});
|
|
7160
|
+
}
|
|
7161
|
+
async function announce({ route, token, zip, mode, declaration, retry }, deps) {
|
|
7162
|
+
let answer;
|
|
7163
|
+
try {
|
|
7164
|
+
answer = await deps.request(route, {
|
|
7165
|
+
token,
|
|
7166
|
+
retry,
|
|
7167
|
+
timeoutMs: ANNOUNCE_TIMEOUT_MS,
|
|
7168
|
+
body: announceRequestBody(zip.byteLength, (0, import_node_crypto2.createHash)("sha256").update(zip).digest("hex"), mode)
|
|
7169
|
+
});
|
|
7170
|
+
} catch (err2) {
|
|
7171
|
+
if (err2 instanceof ApiError && (err2.code === "direct_upload_unavailable" || err2.code === "missing_zip")) {
|
|
7172
|
+
const [size, allowed] = sizeOverLimit(zip.byteLength, maxInlineZipBytes(mode, declaration));
|
|
7173
|
+
throw new ApiError(
|
|
7174
|
+
err2.status,
|
|
7175
|
+
"direct_upload_unavailable",
|
|
7176
|
+
`The upload is ${size} compressed, and the platform does not take uploads of that size at the moment \u2014 only up to ${allowed}. Nothing was uploaded. Try again later.`
|
|
7177
|
+
);
|
|
7178
|
+
}
|
|
7179
|
+
throw err2;
|
|
7180
|
+
}
|
|
7181
|
+
const headers = answer?.required_headers;
|
|
7182
|
+
const understood = typeof answer?.upload_id === "string" && isHttpUrl(answer?.upload_url) && headers !== null && typeof headers === "object" && !Array.isArray(headers) && Object.values(headers).every((value) => typeof value === "string");
|
|
7183
|
+
if (!understood) {
|
|
7184
|
+
throw new ApiError(
|
|
7185
|
+
0,
|
|
7186
|
+
"invalid_upload_answer",
|
|
7187
|
+
"The platform answered the upload request in a form this version of the CLI does not understand. Nothing was uploaded."
|
|
7188
|
+
);
|
|
7189
|
+
}
|
|
7190
|
+
return { upload_id: answer.upload_id, upload_url: answer.upload_url, required_headers: headers };
|
|
7191
|
+
}
|
|
7192
|
+
function isHttpUrl(value) {
|
|
7193
|
+
if (typeof value !== "string") return false;
|
|
7194
|
+
try {
|
|
7195
|
+
return ["https:", "http:"].includes(new URL(value).protocol);
|
|
7196
|
+
} catch {
|
|
7197
|
+
return false;
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
async function putZip(ticket, zip, deps) {
|
|
7201
|
+
const deadline = Date.now() + PUT_TIMEOUT_MS;
|
|
7202
|
+
for (let attempt = 1; ; attempt++) {
|
|
7203
|
+
let failure;
|
|
7204
|
+
let again = attempt < PUT_ATTEMPTS;
|
|
7205
|
+
try {
|
|
7206
|
+
const resp = await deps.fetch(ticket.upload_url, {
|
|
7207
|
+
method: "PUT",
|
|
7208
|
+
headers: ticket.required_headers,
|
|
7209
|
+
body: zip,
|
|
7210
|
+
signal: AbortSignal.timeout(Math.max(1, deadline - Date.now()))
|
|
7211
|
+
});
|
|
7212
|
+
if (resp.ok) return;
|
|
7213
|
+
const code = /<Code>([\w.]{1,80})<\/Code>/.exec(await resp.text())?.[1];
|
|
7214
|
+
failure = `the storage answered HTTP ${resp.status}${code ? ` (${code})` : ""}`;
|
|
7215
|
+
again &&= resp.status >= 500;
|
|
7216
|
+
} catch (err2) {
|
|
7217
|
+
const timedOut = err2?.name === "TimeoutError";
|
|
7218
|
+
const code = typeof err2?.cause?.code === "string" && /^\w{1,40}$/.test(err2.cause.code) ? ` (${err2.cause.code})` : "";
|
|
7219
|
+
failure = timedOut ? `it did not finish within ${PUT_TIMEOUT_MS / 6e4} minutes` : `the connection to the storage broke${code}`;
|
|
7220
|
+
again &&= !timedOut;
|
|
7221
|
+
}
|
|
7222
|
+
if (!again) {
|
|
7223
|
+
throw new ApiError(
|
|
7224
|
+
0,
|
|
7225
|
+
"upload_failed",
|
|
7226
|
+
`The upload did not go through: ${failure}. Nothing of the project was changed \u2014 run the push again.`
|
|
7227
|
+
);
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
|
|
7031
7232
|
// src/lib/pushReport.ts
|
|
7032
7233
|
init_branding();
|
|
7033
7234
|
var EXCLUDE_REASON = {
|
|
@@ -7088,7 +7289,7 @@ function renderAnalysis(analysis, options = {}) {
|
|
|
7088
7289
|
lines.push(" HTML files found:");
|
|
7089
7290
|
for (const candidate of analysis.entry.candidates.slice(0, SHOWN_FILES)) {
|
|
7090
7291
|
lines.push(
|
|
7091
|
-
` ${sizeColumn(candidate.bytes)} ${candidate.path}` + (candidate.title ? paint.dim(` "${candidate.title}"`) : "") + (candidate.same_content_as ? paint.dim(` (same content as ${candidate.same_content_as})`) : "")
|
|
7292
|
+
` ${sizeColumn(candidate.bytes)} ${candidate.path}` + (candidate.title ? paint.dim(` "${candidate.title}"`) : "") + (candidate.same_content_as ? paint.dim(` (same content as ${candidate.same_content_as})`) : "") + (candidate.larger_than_a_push ? paint.dim(" (larger than a whole push)") : "")
|
|
7092
7293
|
);
|
|
7093
7294
|
}
|
|
7094
7295
|
lines.push(...more(analysis.entry.candidates.length, SHOWN_FILES, "HTML file"));
|
|
@@ -7569,7 +7770,7 @@ async function pushCommand(opts) {
|
|
|
7569
7770
|
ui.step(mode === "source" ? "Packing source tree\u2026" : `Packing built output (${rootDir})\u2026`);
|
|
7570
7771
|
const declaration = mode === "source" ? readBackendDeclaration() : null;
|
|
7571
7772
|
const files = collectFiles(rootDir, mode);
|
|
7572
|
-
const zip =
|
|
7773
|
+
const zip = zipFiles(files, maxZipBytesForUpload());
|
|
7573
7774
|
ui.info(`${zip.count} files, ${(zip.bytes / 1024).toFixed(0)} KiB compressed`);
|
|
7574
7775
|
if (declaration) {
|
|
7575
7776
|
const consent = await ensureDatabaseConsent({
|
|
@@ -7587,15 +7788,14 @@ async function pushCommand(opts) {
|
|
|
7587
7788
|
}
|
|
7588
7789
|
}
|
|
7589
7790
|
ui.step("Uploading to your workspace\u2026");
|
|
7590
|
-
const upload = await
|
|
7591
|
-
`${API_URL}/api/workspaces/${userId}/${projectId}/source-zip`,
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
);
|
|
7791
|
+
const upload = await uploadZip({
|
|
7792
|
+
route: `${API_URL}/api/workspaces/${userId}/${projectId}/source-zip`,
|
|
7793
|
+
token: auth.pb_token,
|
|
7794
|
+
zip: zip.data,
|
|
7795
|
+
mode,
|
|
7796
|
+
declaration,
|
|
7797
|
+
retry: platformRetry
|
|
7798
|
+
});
|
|
7599
7799
|
ui.info(`${upload.files_written} files written`);
|
|
7600
7800
|
if (mode === "source") {
|
|
7601
7801
|
ui.step("Building in the cloud (this can take a few minutes)\u2026");
|
|
@@ -7810,7 +8010,7 @@ init_branding();
|
|
|
7810
8010
|
|
|
7811
8011
|
// src/lib/engine.ts
|
|
7812
8012
|
var import_node_fs11 = require("fs");
|
|
7813
|
-
var
|
|
8013
|
+
var import_node_crypto3 = require("crypto");
|
|
7814
8014
|
var import_node_path13 = require("path");
|
|
7815
8015
|
var import_node_os4 = require("os");
|
|
7816
8016
|
var import_node_child_process3 = require("child_process");
|
|
@@ -7867,7 +8067,7 @@ async function fetchManifest() {
|
|
|
7867
8067
|
}
|
|
7868
8068
|
}
|
|
7869
8069
|
async function sha256File(path) {
|
|
7870
|
-
const hash = (0,
|
|
8070
|
+
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
7871
8071
|
await (0, import_promises3.pipeline)((0, import_node_fs11.createReadStream)(path), hash);
|
|
7872
8072
|
return hash.digest("hex");
|
|
7873
8073
|
}
|
|
@@ -8184,7 +8384,7 @@ site can never be uploaded in several parts.
|
|
|
8184
8384
|
source), and Managed Server Actions and \`.agentful/backend.json\` are NOT
|
|
8185
8385
|
deployed by it.
|
|
8186
8386
|
|
|
8187
|
-
Limits of one push, either way:
|
|
8387
|
+
Limits of one push, either way: ${formatBytes(MAX_UNPACKED_BYTES)} of files (their sizes added up), ${formatBytes(maxZipBytesForUpload(), "down")} compressed, ${MAX_UPLOAD_FILES.toLocaleString("en-US")} files.
|
|
8188
8388
|
\`--force\` lifts none of them: it only lets the cloud build try despite a
|
|
8189
8389
|
compatibility finding.
|
|
8190
8390
|
|
|
@@ -8193,36 +8393,60 @@ compatibility finding.
|
|
|
8193
8393
|
reports what a push would upload: no sign-in, no project, no upload, nothing
|
|
8194
8394
|
written. Sizes, limits, what is left out and what blocks the upload come from
|
|
8195
8395
|
that report and from nowhere else: quote its figures, never estimate or
|
|
8196
|
-
recompute them
|
|
8197
|
-
|
|
8198
|
-
|
|
8396
|
+
recompute them. Next to every byte count the report prints the size as text
|
|
8397
|
+
(\`size\` for \`bytes\`, \`zip_size\` for \`zip_bytes\`): use that text, do not
|
|
8398
|
+
convert bytes yourself. \`limits.max_unpacked_bytes\` is the limit a site
|
|
8399
|
+
runs into: the sizes of its files added up. Run it before the first push of a
|
|
8400
|
+
session, after a push was stopped,
|
|
8401
|
+
and after you changed what gets uploaded. In between, \`agentful push\` applies the same
|
|
8199
8402
|
check itself and stops before sign-in when something blocks. A blocker with
|
|
8200
8403
|
\`"overridable": false\` is final, the platform rejects that upload: do not
|
|
8201
8404
|
retry, do not add \`--force\`, do not look for another route.
|
|
8202
8405
|
|
|
8203
8406
|
Every change to the user's files for a push (including \`.gitignore\`) and every
|
|
8204
8407
|
project script you run for it needs the user's OK first: name the concrete
|
|
8205
|
-
change, ask, wait for the answer.
|
|
8408
|
+
change, ask, wait for the answer. One question per reply: one decision, not
|
|
8409
|
+
several joined together. Never ask what the report or the project files
|
|
8410
|
+
answer, such as whether a \`.gitignore\` is in effect
|
|
8411
|
+
(\`excluded.gitignore_applied\`), which files are large or which are copies.
|
|
8206
8412
|
|
|
8207
8413
|
- **No start page** (\`entry_missing\`): the platform serves \`index.html\` from
|
|
8208
8414
|
the top level. With \`entry.candidates\`: show them (path and title;
|
|
8209
|
-
\`same_content_as\` marks copies
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
\`
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8415
|
+
\`same_content_as\` marks copies, \`larger_than_a_push\` marks pages no push
|
|
8416
|
+
can carry: they cannot be the start page as they are, say so) and ask which
|
|
8417
|
+
of the others opens first. A candidate at the top level can be renamed to
|
|
8418
|
+
\`index.html\`, or copied, which keeps the old address and adds the file's
|
|
8419
|
+
size to the upload: ask which. A candidate in a subfolder must not be copied
|
|
8420
|
+
up, its relative links would break. If that folder is the whole site, push
|
|
8421
|
+
the folder (\`suggestions\` carries the command); otherwise adjust the links
|
|
8422
|
+
and show the diff. Without candidates, ask which folder holds the site.
|
|
8423
|
+
- **Too large or too many files** (\`unpacked_too_large\`, \`zip_too_large\`,
|
|
8424
|
+
\`too_many_files\`): settle first whether the site can fit at all. A size
|
|
8425
|
+
blocker names the files that are each larger than a whole push on their own
|
|
8426
|
+
(all of them in its \`paths\`), and its message says what is left without
|
|
8427
|
+
them. Such a file can only stay out. If
|
|
8428
|
+
the site needs one of them (the page the user wants as the start page, or a
|
|
8429
|
+
file a page loads: search the sources for references), the site cannot be
|
|
8430
|
+
pushed yet: say that plainly, with the file and its size. Do not offer
|
|
8431
|
+
\`.gitignore\` or a prebuilt push as a way around it, neither lifts a limit,
|
|
8432
|
+
and larger uploads are not available.
|
|
8433
|
+
Where no such file is needed: explain where the size is, from
|
|
8434
|
+
\`largest_files\`, \`by_top_level\`, \`duplicates\` and \`embedded_media\` (media
|
|
8435
|
+
stored inside text files as \`data:\` URLs), and propose which files the site
|
|
8436
|
+
does not load to leave out with \`.gitignore\`. The \`exclude_with_gitignore\`
|
|
8437
|
+
suggestion says how much has to stay out; if the site needs more than fits,
|
|
8438
|
+
say plainly that it cannot be pushed yet. Before proposing to leave a file
|
|
8439
|
+
out, search the sources for references to it and say what you checked:
|
|
8440
|
+
identical content does not make a copy unused. A prebuilt push is smaller
|
|
8441
|
+
than a source push only where a build produces the output folder; a site
|
|
8442
|
+
without a build step is the same upload either way. Never shrink,
|
|
8443
|
+
re-encode, move or delete the user's files on your own.
|
|
8444
|
+
- **Files the preview does not show** (\`preview_file_too_large\`,
|
|
8445
|
+
\`preview_type_not_delivered\` in \`warnings\`): the push goes through, but
|
|
8446
|
+
the preview does not deliver these files, so a page that needs one of them
|
|
8447
|
+
looks broken there. Say which files and why, with the wording of the
|
|
8448
|
+
warning, and ask whether to push anyway. Never shrink, convert or split
|
|
8449
|
+
them on your own.
|
|
8226
8450
|
- **Compatibility findings** (\`"overridable": true\`): fix the cause in the
|
|
8227
8451
|
code. \`--force\` only when the user asks to try the cloud build anyway.
|
|
8228
8452
|
- **Files that would be missing on the site:** the warnings
|
|
@@ -8416,7 +8640,7 @@ ${backendSessionLines(backend)}
|
|
|
8416
8640
|
}
|
|
8417
8641
|
|
|
8418
8642
|
// src/branding/commands.ts
|
|
8419
|
-
var PUSH_TOOL_TIMEOUT_MS =
|
|
8643
|
+
var PUSH_TOOL_TIMEOUT_MS = 156e4;
|
|
8420
8644
|
var NEEDS_A_PUSH = 'If the command reports "No Agentful project here", nothing has been deployed from this directory yet \u2014 run `agentful push` first (it creates the project and a preview), then retry.';
|
|
8421
8645
|
var SLASH_COMMANDS = {
|
|
8422
8646
|
setup: {
|
|
@@ -8434,8 +8658,8 @@ var SLASH_COMMANDS = {
|
|
|
8434
8658
|
description: `${brand.displayName}: check, deploy and get a preview URL`,
|
|
8435
8659
|
template: `Deploy this project, following "Pushing to the platform" in AGENTFUL_CLOUD.md. Run every command from the project root using the bash tool. What I typed after the command (may be empty): "$ARGUMENTS". If it names \`--prebuilt\`, a folder for \`--dir\`, or \`--force\`, pass that on to both commands below.
|
|
8436
8660
|
|
|
8437
|
-
1. Run \`${PUSH_ANALYSIS_COMMAND}\`. It only reads files: no sign-in, no upload. Its JSON report is the only source for sizes, limits and what blocks the upload: quote its figures, never estimate them.
|
|
8438
|
-
2. If the report or the project calls for a decision (a blocker, a file the site needs that would not be uploaded, a build step the cloud does not run), explain the finding in plain words with the figures of the report and ask me how to proceed
|
|
8661
|
+
1. Run \`${PUSH_ANALYSIS_COMMAND}\`. It only reads files: no sign-in, no upload. Its JSON report is the only source for sizes, limits and what blocks the upload: quote its figures as printed (the \`size\` texts next to the byte counts), never estimate or convert them.
|
|
8662
|
+
2. If the report or the project calls for a decision (a blocker, a file the site needs that would not be uploaded or that the preview would not show, a build step the cloud does not run), explain the finding in plain words with the figures of the report. If the report shows that what I want to publish cannot fit (a page or file it needs is larger than a whole push, or it stays above the limits without the files it does not load), say that plainly and do not offer ways out that do not get it under the limits. Otherwise ask me how to proceed: exactly one question per reply, and never one the report or the project files answer. Then wait for my answer. Until then do not change any file, do not run project scripts and do not push.
|
|
8439
8663
|
3. After a change I approved, run the analysis again.
|
|
8440
8664
|
4. When nothing blocks, run \`agentful push\` with the bash tool's \`timeout\` set to ${PUSH_TOOL_TIMEOUT_MS} (milliseconds): the cloud build takes minutes and the default timeout would cut the push off halfway. The command never waits for input. It creates the project automatically if this directory is not linked yet.
|
|
8441
8665
|
5. Report the preview URL on its own line and what the push printed about the backend. If it fails: quote the printed error verbatim, and if the failure happened in the cloud (not before the upload), also run \`agentful build-status\` and quote its phase/error/details as the cause. Diagnose ONLY from those records \u2014 never invent causes, env vars, or settings they do not show.
|
|
@@ -9268,7 +9492,7 @@ function describeModelRoute(model, catalog, localProviders, connectedProviders)
|
|
|
9268
9492
|
}
|
|
9269
9493
|
|
|
9270
9494
|
// src/lib/engineEvents.ts
|
|
9271
|
-
var
|
|
9495
|
+
var import_node_crypto4 = require("crypto");
|
|
9272
9496
|
var import_node_net = require("net");
|
|
9273
9497
|
function payloadOf(event) {
|
|
9274
9498
|
return event.payload && typeof event.payload === "object" ? event.payload : event;
|
|
@@ -9394,7 +9618,7 @@ var EngineLivenessPolicy = class {
|
|
|
9394
9618
|
function engineServerCredentials(env = process.env) {
|
|
9395
9619
|
return {
|
|
9396
9620
|
username: env.OPENCODE_SERVER_USERNAME || void 0,
|
|
9397
|
-
password: env.OPENCODE_SERVER_PASSWORD || (0,
|
|
9621
|
+
password: env.OPENCODE_SERVER_PASSWORD || (0, import_node_crypto4.randomUUID)()
|
|
9398
9622
|
};
|
|
9399
9623
|
}
|
|
9400
9624
|
async function reserveLoopbackPort() {
|