agentful 0.4.14 → 0.4.16
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 +12 -5
- package/dist/index.cjs +333 -100
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ agentful open # open the preview
|
|
|
26
26
|
| `login` / `logout` / `whoami` | Browser-based sign-in; the token is kept in the macOS Keychain (on Linux: a `0600` file under `~/.config/agentful/`) |
|
|
27
27
|
| `init [--link <id>] [--title <t>]` | Create a cloud project or link an existing one (`.agentful/project.json`) |
|
|
28
28
|
| `push [--prebuilt [--dir <path>]]` | Upload the source and build in the cloud; `--prebuilt` uploads a local build |
|
|
29
|
-
| `push --dry-run [--json]` | Analyse what a push would upload and what would block it — uploads nothing |
|
|
29
|
+
| `push --dry-run [--json [--summary]]` | Analyse what a push would upload and what would block it — uploads nothing |
|
|
30
30
|
| `open` | Open the live preview |
|
|
31
31
|
| `share [--private]` | Make the preview public, or private again |
|
|
32
32
|
| `publish <subdomain>` | Publish at `https://<subdomain>.agentful.page` |
|
|
@@ -39,6 +39,9 @@ agentful open # open the preview
|
|
|
39
39
|
|
|
40
40
|
Inside the interface, `/` lists the Agentful commands (`/setup`, `/push`,
|
|
41
41
|
`/preview`, `/publish`, `/share`, `/status`) alongside the built-in ones.
|
|
42
|
+
`/push` checks before it uploads: the agent reads the same analysis as
|
|
43
|
+
`push --dry-run`, explains what would block the upload or go missing on the
|
|
44
|
+
site, and asks you before it changes a file or pushes.
|
|
42
45
|
|
|
43
46
|
`push` respects your `.gitignore` and always excludes `.git`, `node_modules`,
|
|
44
47
|
build output and every `.env` file. A push carries at most about 4.4 MiB
|
|
@@ -48,10 +51,14 @@ in or creates a project.
|
|
|
48
51
|
|
|
49
52
|
`agentful push --dry-run` shows that check on its own: what would be uploaded
|
|
50
53
|
and what is left out, the largest files, identical copies, media embedded in
|
|
51
|
-
HTML, and every reason the upload would be rejected.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
HTML, and every reason the upload would be rejected. A file that is larger
|
|
55
|
+
than a whole push on its own is named as such: it cannot be uploaded at all,
|
|
56
|
+
whatever else is left out. It uploads nothing, creates no project and changes
|
|
57
|
+
no file; it exits with 1 when the push would be blocked. `--dry-run --json`
|
|
58
|
+
prints the same analysis as one JSON document
|
|
59
|
+
(`"schema": "agentful.push-analysis"`) for scripts and agents; with `--summary`
|
|
60
|
+
it leaves out the list of every file, keeps totals, limits and findings, and
|
|
61
|
+
prints every size as text next to its byte count.
|
|
55
62
|
|
|
56
63
|
## What you can deploy
|
|
57
64
|
|
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.16" ? "0.4.16" : null.version;
|
|
3048
3048
|
brand = {
|
|
3049
3049
|
name: "agentful",
|
|
3050
3050
|
// the command users type
|
|
@@ -6561,7 +6561,7 @@ function formatBytes(bytes2, rounding = "nearest") {
|
|
|
6561
6561
|
}
|
|
6562
6562
|
if (unit === 0 || Number.isInteger(value)) return `${value} ${units[unit]}`;
|
|
6563
6563
|
const tenths = value * 10;
|
|
6564
|
-
const rounded = (rounding === "down" ? Math.floor(tenths) : Math.round(tenths)) / 10;
|
|
6564
|
+
const rounded = (rounding === "down" ? Math.floor(tenths) : rounding === "up" ? Math.ceil(tenths) : Math.round(tenths)) / 10;
|
|
6565
6565
|
return `${rounded.toFixed(1)} ${units[unit]}`;
|
|
6566
6566
|
}
|
|
6567
6567
|
function sizeOverLimit(bytes2, limit) {
|
|
@@ -6606,6 +6606,7 @@ function failedAnalysis(mode, projectDir, blocker) {
|
|
|
6606
6606
|
schema: ANALYSIS_SCHEMA,
|
|
6607
6607
|
schema_version: ANALYSIS_SCHEMA_VERSION,
|
|
6608
6608
|
cli_version: VERSION,
|
|
6609
|
+
view: "full",
|
|
6609
6610
|
mode,
|
|
6610
6611
|
root: null,
|
|
6611
6612
|
ok: false,
|
|
@@ -6727,6 +6728,10 @@ function analyzePush(options) {
|
|
|
6727
6728
|
}
|
|
6728
6729
|
duplicates.sort((a, b) => b.redundant_zip_bytes - a.redundant_zip_bytes || (a.paths[0] < b.paths[0] ? -1 : 1));
|
|
6729
6730
|
const redundantZipBytes = duplicates.reduce((total, group) => total + group.redundant_zip_bytes, 0);
|
|
6731
|
+
const maxZipBytes = maxZipBytesForUpload(mode, mode === "source" ? readBackendDeclaration(rootDir) : null);
|
|
6732
|
+
const oversized = measured.filter((file) => file.zipLower > maxZipBytes).sort((a, b) => b.zipLower - a.zipLower || byPath(a, b));
|
|
6733
|
+
const oversizedPaths = new Set(oversized.map((file) => file.path));
|
|
6734
|
+
const restZipLower = zipLower - oversized.reduce((total, file) => total + file.zipLower, 0);
|
|
6730
6735
|
const preflight = mode === "source" ? runPreflight(rootDir) : null;
|
|
6731
6736
|
const framework = preflight?.framework ?? null;
|
|
6732
6737
|
const hasManifest = storedNames.has("package.json");
|
|
@@ -6738,12 +6743,14 @@ function analyzePush(options) {
|
|
|
6738
6743
|
return {
|
|
6739
6744
|
path: file.path,
|
|
6740
6745
|
bytes: file.bytes,
|
|
6746
|
+
zip_bytes: file.zip_bytes,
|
|
6741
6747
|
title: file.title,
|
|
6742
6748
|
sha256: file.sha256,
|
|
6743
|
-
same_content_as: first && first !== file.path ? first : null
|
|
6749
|
+
same_content_as: first && first !== file.path ? first : null,
|
|
6750
|
+
...file.zipLower > maxZipBytes ? { larger_than_a_push: true } : {}
|
|
6744
6751
|
};
|
|
6745
6752
|
});
|
|
6746
|
-
const
|
|
6753
|
+
const fittingCandidates = candidates.filter((candidate) => !candidate.larger_than_a_push);
|
|
6747
6754
|
const zipLimit = formatBytes(maxZipBytes, "down");
|
|
6748
6755
|
const blockers = [];
|
|
6749
6756
|
const warnings = [];
|
|
@@ -6781,10 +6788,18 @@ function analyzePush(options) {
|
|
|
6781
6788
|
}
|
|
6782
6789
|
if (zipLower > maxZipBytes) {
|
|
6783
6790
|
const [size, allowed] = sizeOverLimit(zipExact ? zipBytes : zipLower, maxZipBytes);
|
|
6791
|
+
let message = `The upload is ${zipExact ? "" : "at least "}${size} compressed \u2014 a push carries at most ${allowed} compressed.`;
|
|
6792
|
+
if (oversized.length > 0) {
|
|
6793
|
+
const one = oversized.length === 1;
|
|
6794
|
+
const named = samplePaths(oversized.map((file) => `${file.path} (${sizeOverLimit(file.zipLower, maxZipBytes)[0]})`));
|
|
6795
|
+
message += one ? ` ${named} is larger than that on its own, so no push can carry it.` : ` ${plural(oversized.length, "file")} are each larger than that on their own, so no push can carry them: ${named}.`;
|
|
6796
|
+
message += ` Without ${one ? "it" : "them"} the upload is ${restZipLower > maxZipBytes ? `still ${sizeOverLimit(restZipLower, maxZipBytes)[0]} compressed` : `${formatBytes(restZipLower)} compressed, which is within that limit`}.`;
|
|
6797
|
+
}
|
|
6784
6798
|
blockers.push({
|
|
6785
6799
|
code: "zip_too_large",
|
|
6786
6800
|
overridable: false,
|
|
6787
|
-
message
|
|
6801
|
+
message,
|
|
6802
|
+
...oversized.length > 0 ? { paths: oversized.map((file) => file.path).slice(0, FINDING_PATHS) } : {}
|
|
6788
6803
|
});
|
|
6789
6804
|
} else if (!zipExact && zipBytes > maxZipBytes) {
|
|
6790
6805
|
warnings.push({
|
|
@@ -6793,10 +6808,12 @@ function analyzePush(options) {
|
|
|
6793
6808
|
});
|
|
6794
6809
|
}
|
|
6795
6810
|
if (entryMissing) {
|
|
6811
|
+
const tooBig = candidates.filter((candidate) => candidate.larger_than_a_push);
|
|
6812
|
+
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))}.`;
|
|
6796
6813
|
blockers.push({
|
|
6797
6814
|
code: "entry_missing",
|
|
6798
6815
|
overridable: false,
|
|
6799
|
-
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."
|
|
6816
|
+
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
|
|
6800
6817
|
});
|
|
6801
6818
|
}
|
|
6802
6819
|
const backend = mode === "source" ? checkBackendDeclaration(rootDir) : null;
|
|
@@ -6837,11 +6854,11 @@ function analyzePush(options) {
|
|
|
6837
6854
|
}
|
|
6838
6855
|
const tooLarge = blockers.some((b) => b.code === "zip_too_large" || b.code === "unpacked_too_large");
|
|
6839
6856
|
if (entryMissing) {
|
|
6840
|
-
if (
|
|
6857
|
+
if (fittingCandidates.length > 0) {
|
|
6841
6858
|
suggestions.push({
|
|
6842
6859
|
code: "name_start_page",
|
|
6843
6860
|
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.",
|
|
6844
|
-
paths:
|
|
6861
|
+
paths: fittingCandidates.map((candidate) => candidate.path).slice(0, FINDING_PATHS)
|
|
6845
6862
|
});
|
|
6846
6863
|
}
|
|
6847
6864
|
const siteDirs = /* @__PURE__ */ new Set();
|
|
@@ -6863,29 +6880,31 @@ function analyzePush(options) {
|
|
|
6863
6880
|
}
|
|
6864
6881
|
}
|
|
6865
6882
|
if (tooLarge) {
|
|
6866
|
-
const
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6883
|
+
const overZip = zipLower - maxZipBytes;
|
|
6884
|
+
const overFiles = storedBytes - MAX_UNPACKED_BYTES;
|
|
6885
|
+
const mustStayOut = [
|
|
6886
|
+
overZip > 0 ? `${formatBytes(overZip, "up")} of the ${formatBytes(zipLower)} compressed` : "",
|
|
6887
|
+
overFiles > 0 ? `${formatBytes(overFiles, "up")} of the ${formatBytes(storedBytes)} of files` : ""
|
|
6888
|
+
].filter(Boolean);
|
|
6889
|
+
const toFit = ` To fit, at least ${mustStayOut.join(" and ")} ${mustStayOut.length > 1 ? "have" : "has"} to stay out.`;
|
|
6890
|
+
const spareCopies = duplicates.filter((group) => !oversizedPaths.has(group.paths[0]));
|
|
6891
|
+
const spareZipBytes = spareCopies.reduce((total, group) => total + group.redundant_zip_bytes, 0);
|
|
6892
|
+
const base = oversized.length > 0 ? restZipLower : zipBytes;
|
|
6893
|
+
if (spareCopies.length > 0 && spareZipBytes >= base / 20) {
|
|
6894
|
+
const copies = spareCopies.reduce((total, group) => total + group.paths.length - 1, 0);
|
|
6895
|
+
const remaining = base - spareZipBytes;
|
|
6877
6896
|
suggestions.push({
|
|
6878
6897
|
code: "remove_identical_copies",
|
|
6879
|
-
message: `${plural(copies, "file is an identical copy", "files are identical copies")} of another file and ${copies === 1 ? "adds" : "add"} ${formatBytes(
|
|
6880
|
-
paths:
|
|
6898
|
+
message: `${plural(copies, "file is an identical copy", "files are identical copies")} of another file and ${copies === 1 ? "adds" : "add"} ${formatBytes(spareZipBytes)} to the 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 > maxZipBytes ? ` \u2014 still above the ${zipLimit} limit` : ""}.`,
|
|
6899
|
+
paths: spareCopies.flatMap((group) => group.paths.slice(1)).slice(0, FINDING_PATHS)
|
|
6881
6900
|
});
|
|
6882
6901
|
}
|
|
6883
6902
|
suggestions.push(mode === "source" ? {
|
|
6884
6903
|
code: "exclude_with_gitignore",
|
|
6885
|
-
message:
|
|
6904
|
+
message: `Files and folders listed in .gitignore are not uploaded. Leave out what the site does not serve \u2014 originals, working files, exports.${toFit}`
|
|
6886
6905
|
} : {
|
|
6887
6906
|
code: "narrow_prebuilt_directory",
|
|
6888
|
-
message:
|
|
6907
|
+
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}`
|
|
6889
6908
|
});
|
|
6890
6909
|
suggestions.push({
|
|
6891
6910
|
code: "upload_limit",
|
|
@@ -6911,6 +6930,7 @@ function analyzePush(options) {
|
|
|
6911
6930
|
schema: ANALYSIS_SCHEMA,
|
|
6912
6931
|
schema_version: ANALYSIS_SCHEMA_VERSION,
|
|
6913
6932
|
cli_version: VERSION,
|
|
6933
|
+
view: "full",
|
|
6914
6934
|
mode,
|
|
6915
6935
|
root: rootDir,
|
|
6916
6936
|
ok: blockers.length === 0,
|
|
@@ -6947,6 +6967,93 @@ function analyzePush(options) {
|
|
|
6947
6967
|
fingerprint: `sha256:${fingerprint}`
|
|
6948
6968
|
};
|
|
6949
6969
|
}
|
|
6970
|
+
var SUMMARY_LISTS = {
|
|
6971
|
+
largest_files: 8,
|
|
6972
|
+
by_top_level: 8,
|
|
6973
|
+
duplicates: 8,
|
|
6974
|
+
duplicate_paths: 8,
|
|
6975
|
+
embedded_media: 8,
|
|
6976
|
+
entry_candidates: 20,
|
|
6977
|
+
excluded_entries: 30,
|
|
6978
|
+
dropped_by_platform: 20,
|
|
6979
|
+
finding_paths: 8
|
|
6980
|
+
};
|
|
6981
|
+
var SUMMARY_MAX_BYTES = 24 * 1024;
|
|
6982
|
+
var sizeLabelKey = (key) => key === "base64_chars" ? "base64_size" : /(^|_)bytes(_|$)/.test(key) ? key.replace("bytes", "size") : null;
|
|
6983
|
+
function withSizeLabels(value) {
|
|
6984
|
+
if (Array.isArray(value)) return value.map(withSizeLabels);
|
|
6985
|
+
if (!value || typeof value !== "object") return value;
|
|
6986
|
+
const labelled = {};
|
|
6987
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
6988
|
+
labelled[key] = withSizeLabels(inner);
|
|
6989
|
+
const label = typeof inner === "number" ? sizeLabelKey(key) : null;
|
|
6990
|
+
if (label) labelled[label] = formatBytes(inner, key.startsWith("max_") ? "down" : "nearest");
|
|
6991
|
+
}
|
|
6992
|
+
return labelled;
|
|
6993
|
+
}
|
|
6994
|
+
var printAnalysis = (analysis) => `${JSON.stringify(analysis.view === "summary" ? withSizeLabels(analysis) : analysis, null, 2)}
|
|
6995
|
+
`;
|
|
6996
|
+
function summarize(analysis, divisor) {
|
|
6997
|
+
const shortened = {};
|
|
6998
|
+
const cut = (name, list, cap, alreadyOmitted = 0) => {
|
|
6999
|
+
const keep = Math.max(1, Math.floor(cap / divisor));
|
|
7000
|
+
const omitted = Math.max(0, list.length - keep) + alreadyOmitted;
|
|
7001
|
+
if (omitted > 0) shortened[name] = (shortened[name] ?? 0) + omitted;
|
|
7002
|
+
return list.slice(0, keep);
|
|
7003
|
+
};
|
|
7004
|
+
const finding = (kind) => (item) => item.paths ? { ...item, paths: cut(`${kind}.paths`, item.paths, SUMMARY_LISTS.finding_paths) } : item;
|
|
7005
|
+
if (analysis.totals.files > 0) shortened.files = analysis.totals.files;
|
|
7006
|
+
const excludedEntries = cut(
|
|
7007
|
+
"excluded.entries",
|
|
7008
|
+
analysis.excluded.entries,
|
|
7009
|
+
SUMMARY_LISTS.excluded_entries,
|
|
7010
|
+
analysis.excluded.omitted
|
|
7011
|
+
);
|
|
7012
|
+
return {
|
|
7013
|
+
schema: analysis.schema,
|
|
7014
|
+
schema_version: analysis.schema_version,
|
|
7015
|
+
cli_version: analysis.cli_version,
|
|
7016
|
+
view: "summary",
|
|
7017
|
+
shortened,
|
|
7018
|
+
mode: analysis.mode,
|
|
7019
|
+
root: analysis.root,
|
|
7020
|
+
ok: analysis.ok,
|
|
7021
|
+
framework: analysis.framework,
|
|
7022
|
+
project: analysis.project,
|
|
7023
|
+
limits: analysis.limits,
|
|
7024
|
+
totals: analysis.totals,
|
|
7025
|
+
blockers: analysis.blockers.map(finding("blockers")),
|
|
7026
|
+
// The note about the cap of the full file list describes a list that is not here.
|
|
7027
|
+
warnings: analysis.warnings.filter((warning) => warning.code !== "file_list_truncated").map(finding("warnings")),
|
|
7028
|
+
suggestions: analysis.suggestions.map(finding("suggestions")),
|
|
7029
|
+
entry: {
|
|
7030
|
+
...analysis.entry,
|
|
7031
|
+
candidates: cut("entry.candidates", analysis.entry.candidates, SUMMARY_LISTS.entry_candidates)
|
|
7032
|
+
},
|
|
7033
|
+
flattened_prefix: analysis.flattened_prefix,
|
|
7034
|
+
largest_files: cut("largest_files", analysis.largest_files, SUMMARY_LISTS.largest_files),
|
|
7035
|
+
by_class: analysis.by_class,
|
|
7036
|
+
by_top_level: cut("by_top_level", analysis.by_top_level, SUMMARY_LISTS.by_top_level),
|
|
7037
|
+
duplicates: cut("duplicates", analysis.duplicates, SUMMARY_LISTS.duplicates).map((group) => ({ ...group, paths: cut("duplicates.paths", group.paths, SUMMARY_LISTS.duplicate_paths) })),
|
|
7038
|
+
embedded_media: cut("embedded_media", analysis.embedded_media, SUMMARY_LISTS.embedded_media),
|
|
7039
|
+
excluded: {
|
|
7040
|
+
...analysis.excluded,
|
|
7041
|
+
entries: excludedEntries,
|
|
7042
|
+
omitted: analysis.excluded.omitted + analysis.excluded.entries.length - excludedEntries.length
|
|
7043
|
+
},
|
|
7044
|
+
dropped_by_platform: cut("dropped_by_platform", analysis.dropped_by_platform, SUMMARY_LISTS.dropped_by_platform),
|
|
7045
|
+
files: [],
|
|
7046
|
+
files_omitted: analysis.totals.files,
|
|
7047
|
+
fingerprint: analysis.fingerprint
|
|
7048
|
+
};
|
|
7049
|
+
}
|
|
7050
|
+
function summarizeAnalysis(analysis) {
|
|
7051
|
+
let summary = summarize(analysis, 1);
|
|
7052
|
+
for (let divisor = 2; divisor <= 32 && Buffer.byteLength(printAnalysis(summary), "utf8") > SUMMARY_MAX_BYTES; divisor *= 2) {
|
|
7053
|
+
summary = summarize(analysis, divisor);
|
|
7054
|
+
}
|
|
7055
|
+
return summary;
|
|
7056
|
+
}
|
|
6950
7057
|
function wouldUpload(analysis, force = false) {
|
|
6951
7058
|
return analysis.blockers.every((blocker) => blocker.overridable && force);
|
|
6952
7059
|
}
|
|
@@ -7011,7 +7118,7 @@ function renderAnalysis(analysis, options = {}) {
|
|
|
7011
7118
|
lines.push(" HTML files found:");
|
|
7012
7119
|
for (const candidate of analysis.entry.candidates.slice(0, SHOWN_FILES)) {
|
|
7013
7120
|
lines.push(
|
|
7014
|
-
` ${sizeColumn(candidate.bytes)} ${candidate.path}` + (candidate.title ? paint.dim(` "${candidate.title}"`) : "") + (candidate.same_content_as ? paint.dim(` (same content as ${candidate.same_content_as})`) : "")
|
|
7121
|
+
` ${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)") : "")
|
|
7015
7122
|
);
|
|
7016
7123
|
}
|
|
7017
7124
|
lines.push(...more(analysis.entry.candidates.length, SHOWN_FILES, "HTML file"));
|
|
@@ -7425,6 +7532,13 @@ async function pushCommand(opts) {
|
|
|
7425
7532
|
"--json belongs to --dry-run: `agentful push --dry-run --json` prints the upload analysis and uploads nothing."
|
|
7426
7533
|
);
|
|
7427
7534
|
}
|
|
7535
|
+
if (opts.summary && !opts.json) {
|
|
7536
|
+
throw new ApiError(
|
|
7537
|
+
0,
|
|
7538
|
+
"invalid_options",
|
|
7539
|
+
"--summary belongs to --dry-run --json: it prints the analysis without the list of every file."
|
|
7540
|
+
);
|
|
7541
|
+
}
|
|
7428
7542
|
if (!opts.json) console.log(banner());
|
|
7429
7543
|
const mode = opts.prebuilt ? "dist" : "source";
|
|
7430
7544
|
const cwd = process.cwd();
|
|
@@ -7438,8 +7552,7 @@ async function pushCommand(opts) {
|
|
|
7438
7552
|
analysis = failedAnalysis(mode, cwd, { code: err2.code, message: err2.message });
|
|
7439
7553
|
}
|
|
7440
7554
|
if (opts.dryRun) {
|
|
7441
|
-
if (opts.json) process.stdout.write(
|
|
7442
|
-
`);
|
|
7555
|
+
if (opts.json) process.stdout.write(printAnalysis(opts.summary ? summarizeAnalysis(analysis) : analysis));
|
|
7443
7556
|
else for (const line of renderAnalysis(analysis, { force: opts.force, dryRun: true })) console.log(line);
|
|
7444
7557
|
if (!wouldUpload(analysis, opts.force)) process.exitCode = 1;
|
|
7445
7558
|
return;
|
|
@@ -7968,75 +8081,6 @@ var agentful_theme_default = {
|
|
|
7968
8081
|
|
|
7969
8082
|
// src/branding/commands.ts
|
|
7970
8083
|
init_branding();
|
|
7971
|
-
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.';
|
|
7972
|
-
var SLASH_COMMANDS = {
|
|
7973
|
-
setup: {
|
|
7974
|
-
description: `${brand.displayName}: create or link the cloud project for this directory`,
|
|
7975
|
-
template: 'Check whether .agentful/project.json exists. If it does, report the linked project title and id and stop. Otherwise run `agentful init --title "<name>"` using the bash tool, where <name> is $ARGUMENTS if I gave one, otherwise the current directory name. Report what it created and mention the title I can change it to. Do not modify any other project files.'
|
|
7976
|
-
},
|
|
7977
|
-
push: {
|
|
7978
|
-
description: `${brand.displayName}: deploy this project and get a preview URL`,
|
|
7979
|
-
template: "Run `agentful push` from the project root using the bash tool. It creates the project automatically if this directory is not linked yet. Stream what it prints, and when it finishes report the preview URL on its own line. If it fails: quote the printed error verbatim, and if the failure happened in the cloud (not in the pre-upload preflight), 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. Do not modify project files unless I ask."
|
|
7980
|
-
},
|
|
7981
|
-
"build-status": {
|
|
7982
|
-
description: `${brand.displayName}: show the last cloud build result`,
|
|
7983
|
-
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
|
|
7984
|
-
},
|
|
7985
|
-
backend: {
|
|
7986
|
-
description: `${brand.displayName}: open the Backend tab (managed DB + server actions)`,
|
|
7987
|
-
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
|
|
7988
|
-
},
|
|
7989
|
-
preview: {
|
|
7990
|
-
description: `${brand.displayName}: open the live preview in the browser`,
|
|
7991
|
-
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
|
|
7992
|
-
},
|
|
7993
|
-
publish: {
|
|
7994
|
-
description: `${brand.displayName}: publish on a public subdomain`,
|
|
7995
|
-
template: "Ask me for the subdomain if I did not provide one in $ARGUMENTS, then run `agentful publish <subdomain>` from the project root using the bash tool and report the public URL. " + NEEDS_A_PUSH
|
|
7996
|
-
},
|
|
7997
|
-
share: {
|
|
7998
|
-
description: `${brand.displayName}: make the live preview public (or private again)`,
|
|
7999
|
-
template: "Run `agentful share` from the project root using the bash tool (add `--private` if $ARGUMENTS says private) and report the resulting visibility and URL. " + NEEDS_A_PUSH
|
|
8000
|
-
},
|
|
8001
|
-
status: {
|
|
8002
|
-
description: `${brand.displayName}: show the linked project and account`,
|
|
8003
|
-
template: "Run `agentful whoami` using the bash tool. Then read .agentful/project.json and report the linked project title and id, plus the preview URL https://preview-<projectId>.agentful.page/. If the file does not exist, say that this directory is not linked yet and that `/setup` creates the link."
|
|
8004
|
-
}
|
|
8005
|
-
};
|
|
8006
|
-
function commandMarkdown(name) {
|
|
8007
|
-
const cmd = SLASH_COMMANDS[name];
|
|
8008
|
-
const description = JSON.stringify(cmd.description);
|
|
8009
|
-
return `---
|
|
8010
|
-
description: ${description}
|
|
8011
|
-
agent: ${cmd.agent ?? "agentful-build"}
|
|
8012
|
-
---
|
|
8013
|
-
|
|
8014
|
-
${cmd.template}
|
|
8015
|
-
`;
|
|
8016
|
-
}
|
|
8017
|
-
|
|
8018
|
-
// src/lib/tools.ts
|
|
8019
|
-
var import_node_fs13 = require("fs");
|
|
8020
|
-
var import_node_path15 = require("path");
|
|
8021
|
-
function assetsDir() {
|
|
8022
|
-
const here = (0, import_node_path15.dirname)(process.argv[1] || "");
|
|
8023
|
-
for (const candidate of [(0, import_node_path15.join)(here, "..", "assets"), (0, import_node_path15.join)(here, "assets")]) {
|
|
8024
|
-
if ((0, import_node_fs13.existsSync)((0, import_node_path15.join)(candidate, "tools", "imagegen.ts"))) return candidate;
|
|
8025
|
-
}
|
|
8026
|
-
return null;
|
|
8027
|
-
}
|
|
8028
|
-
function installEngineTools(configDir2) {
|
|
8029
|
-
const assets = assetsDir();
|
|
8030
|
-
if (!assets) return false;
|
|
8031
|
-
const target = (0, import_node_path15.join)(configDir2, "tools");
|
|
8032
|
-
(0, import_node_fs13.mkdirSync)(target, { recursive: true });
|
|
8033
|
-
try {
|
|
8034
|
-
(0, import_node_fs13.cpSync)((0, import_node_path15.join)(assets, "tools"), target, { recursive: true });
|
|
8035
|
-
return true;
|
|
8036
|
-
} catch {
|
|
8037
|
-
return false;
|
|
8038
|
-
}
|
|
8039
|
-
}
|
|
8040
8084
|
|
|
8041
8085
|
// src/lib/cloudTarget.ts
|
|
8042
8086
|
var CLOUD_INSTRUCTIONS_FILENAME = "AGENTFUL_CLOUD.md";
|
|
@@ -8146,6 +8190,104 @@ function serverSideSection() {
|
|
|
8146
8190
|
)
|
|
8147
8191
|
].join("\n\n");
|
|
8148
8192
|
}
|
|
8193
|
+
var PUSH_ANALYSIS_COMMAND = "agentful push --dry-run --json --summary";
|
|
8194
|
+
function pushSection() {
|
|
8195
|
+
const excludedDirs = [...ALWAYS_EXCLUDE_DIRS].filter((name) => /^[a-z]/.test(name)).map((name) => `\`${name}\``).join(", ");
|
|
8196
|
+
return `## Pushing to the platform (\`agentful push\`)
|
|
8197
|
+
|
|
8198
|
+
Two ways to upload. Every push replaces the previous upload completely, so a
|
|
8199
|
+
site can never be uploaded in several parts.
|
|
8200
|
+
|
|
8201
|
+
- **Source push**, \`agentful push\`: uploads this directory, then builds it in
|
|
8202
|
+
the cloud. Never uploaded: paths listed in \`.gitignore\`, \`.env*\` files,
|
|
8203
|
+
symlinks, tool folders such as \`.git\` or \`.next\`, and any folder named
|
|
8204
|
+
${excludedDirs}, at any depth.
|
|
8205
|
+
The cloud build runs \`npm ci\` (with a \`package-lock.json\`, otherwise
|
|
8206
|
+
\`npm install\`) and then the build command from the table above. Nothing
|
|
8207
|
+
else runs: no other package manager, no separate data or prepare script, no
|
|
8208
|
+
CI workflow step.
|
|
8209
|
+
- **Prebuilt push**, \`agentful push --prebuilt --dir <folder>\`: uploads a
|
|
8210
|
+
finished output folder and serves it as it is. No cloud build, \`.gitignore\`
|
|
8211
|
+
is not applied, and \`index.html\` must sit at the top of that folder. It
|
|
8212
|
+
carries the website only: the project source in the cloud stays as it was (a
|
|
8213
|
+
later build in the cloud workspace replaces the site with a build of that
|
|
8214
|
+
source), and Managed Server Actions and \`.agentful/backend.json\` are NOT
|
|
8215
|
+
deployed by it.
|
|
8216
|
+
|
|
8217
|
+
Limits of one push, either way: about ${formatBytes(maxZipBytesForUpload(), "down")} compressed, ${formatBytes(MAX_UNPACKED_BYTES)} of files, ${MAX_UPLOAD_FILES.toLocaleString("en-US")} files.
|
|
8218
|
+
\`--force\` lifts none of them: it only lets the cloud build try despite a
|
|
8219
|
+
compatibility finding.
|
|
8220
|
+
|
|
8221
|
+
**The analysis decides, not an estimate.** \`${PUSH_ANALYSIS_COMMAND}\`
|
|
8222
|
+
(with \`--prebuilt --dir <folder>\` for a prebuilt push) reads the files and
|
|
8223
|
+
reports what a push would upload: no sign-in, no project, no upload, nothing
|
|
8224
|
+
written. Sizes, limits, what is left out and what blocks the upload come from
|
|
8225
|
+
that report and from nowhere else: quote its figures, never estimate or
|
|
8226
|
+
recompute them. Next to every byte count the report prints the size as text
|
|
8227
|
+
(\`size\` for \`bytes\`, \`zip_size\` for \`zip_bytes\`): use that text, do not
|
|
8228
|
+
convert bytes yourself. \`limits.max_zip_bytes\` is the exact limit for this
|
|
8229
|
+
push. Run it before the first push of a session, after a push was stopped,
|
|
8230
|
+
and after you changed what gets uploaded. In between, \`agentful push\` applies the same
|
|
8231
|
+
check itself and stops before sign-in when something blocks. A blocker with
|
|
8232
|
+
\`"overridable": false\` is final, the platform rejects that upload: do not
|
|
8233
|
+
retry, do not add \`--force\`, do not look for another route.
|
|
8234
|
+
|
|
8235
|
+
Every change to the user's files for a push (including \`.gitignore\`) and every
|
|
8236
|
+
project script you run for it needs the user's OK first: name the concrete
|
|
8237
|
+
change, ask, wait for the answer. One question per reply: one decision, not
|
|
8238
|
+
several joined together. Never ask what the report or the project files
|
|
8239
|
+
answer, such as whether a \`.gitignore\` is in effect
|
|
8240
|
+
(\`excluded.gitignore_applied\`), which files are large or which are copies.
|
|
8241
|
+
|
|
8242
|
+
- **No start page** (\`entry_missing\`): the platform serves \`index.html\` from
|
|
8243
|
+
the top level. With \`entry.candidates\`: show them (path and title;
|
|
8244
|
+
\`same_content_as\` marks copies, \`larger_than_a_push\` marks pages no push
|
|
8245
|
+
can carry: they cannot be the start page as they are, say so) and ask which
|
|
8246
|
+
of the others opens first. A candidate at the top level can be renamed to
|
|
8247
|
+
\`index.html\`, or copied, which keeps the old address and adds the file's
|
|
8248
|
+
size to the upload: ask which. A candidate in a subfolder must not be copied
|
|
8249
|
+
up, its relative links would break. If that folder is the whole site, push
|
|
8250
|
+
the folder (\`suggestions\` carries the command); otherwise adjust the links
|
|
8251
|
+
and show the diff. Without candidates, ask which folder holds the site.
|
|
8252
|
+
- **Too large or too many files** (\`zip_too_large\`, \`unpacked_too_large\`,
|
|
8253
|
+
\`too_many_files\`): settle first whether the site can fit at all. The
|
|
8254
|
+
\`zip_too_large\` blocker names the files that are each larger than a whole
|
|
8255
|
+
push on their own (all of them in its \`paths\`), and its message says what
|
|
8256
|
+
is left without them. Such a file can only stay out. If
|
|
8257
|
+
the site needs one of them (the page the user wants as the start page, or a
|
|
8258
|
+
file a page loads: search the sources for references), the site cannot be
|
|
8259
|
+
pushed yet: say that plainly, with the file and its size. Do not offer
|
|
8260
|
+
\`.gitignore\` or a prebuilt push as a way around it, neither lifts a limit,
|
|
8261
|
+
and larger uploads are not available.
|
|
8262
|
+
Where no such file is needed: explain where the size is, from
|
|
8263
|
+
\`largest_files\`, \`by_top_level\`, \`duplicates\` and \`embedded_media\` (media
|
|
8264
|
+
stored inside text files as \`data:\` URLs), and propose which files the site
|
|
8265
|
+
does not load to leave out with \`.gitignore\`. The \`exclude_with_gitignore\`
|
|
8266
|
+
suggestion says how much has to stay out; if the site needs more than fits,
|
|
8267
|
+
say plainly that it cannot be pushed yet. Before proposing to leave a file
|
|
8268
|
+
out, search the sources for references to it and say what you checked:
|
|
8269
|
+
identical content does not make a copy unused. A prebuilt push is smaller
|
|
8270
|
+
than a source push only where a build produces the output folder; a site
|
|
8271
|
+
without a build step is the same upload either way. Never shrink,
|
|
8272
|
+
re-encode, move or delete the user's files on your own.
|
|
8273
|
+
- **Compatibility findings** (\`"overridable": true\`): fix the cause in the
|
|
8274
|
+
code. \`--force\` only when the user asks to try the cloud build anyway.
|
|
8275
|
+
- **Files that would be missing on the site:** the warnings
|
|
8276
|
+
\`dropped_by_platform\` and \`excluded_static_directory\`, and entries of
|
|
8277
|
+
\`excluded.entries\` with reason \`gitignore\` that the site loads at runtime
|
|
8278
|
+
(generated data under \`public/\`, for example). The build can succeed and the
|
|
8279
|
+
site still be broken: tell the user before pushing and ask.
|
|
8280
|
+
- **Steps the cloud build does not run:** before the first push of a project
|
|
8281
|
+
you did not create in this session, read the \`package.json\` scripts, the
|
|
8282
|
+
README and the CI workflows for data generation, code generation or another
|
|
8283
|
+
package manager. If the site needs such a step, a source push is the wrong
|
|
8284
|
+
way: build locally with the project's own commands and its real data, keep
|
|
8285
|
+
its checks, and push the output folder prebuilt. Never put sample data in
|
|
8286
|
+
place of real data to get a push through.
|
|
8287
|
+
|
|
8288
|
+
A finished build or upload does not prove that the site works: say what you
|
|
8289
|
+
verified and what you did not.`;
|
|
8290
|
+
}
|
|
8149
8291
|
function renderCloudInstructions(framework, backend) {
|
|
8150
8292
|
return `# Agentful Cloud target (platform contract)
|
|
8151
8293
|
|
|
@@ -8300,6 +8442,8 @@ user's conscious step \u2014 in that tab, or by answering the question
|
|
|
8300
8442
|
\`agentful push\` asks once (it names both consequences; a non-interactive
|
|
8301
8443
|
push never enables anything).
|
|
8302
8444
|
|
|
8445
|
+
${pushSection()}
|
|
8446
|
+
|
|
8303
8447
|
## Diagnosing failed pushes and cloud builds (hard rule)
|
|
8304
8448
|
|
|
8305
8449
|
Diagnose **only from evidence**: the preflight output of \`agentful push\`, and
|
|
@@ -8318,6 +8462,93 @@ ${backendSessionLines(backend)}
|
|
|
8318
8462
|
`;
|
|
8319
8463
|
}
|
|
8320
8464
|
|
|
8465
|
+
// src/branding/commands.ts
|
|
8466
|
+
var PUSH_TOOL_TIMEOUT_MS = 9e5;
|
|
8467
|
+
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.';
|
|
8468
|
+
var SLASH_COMMANDS = {
|
|
8469
|
+
setup: {
|
|
8470
|
+
description: `${brand.displayName}: create or link the cloud project for this directory`,
|
|
8471
|
+
template: 'Check whether .agentful/project.json exists. If it does, report the linked project title and id and stop. Otherwise run `agentful init --title "<name>"` using the bash tool, where <name> is $ARGUMENTS if I gave one, otherwise the current directory name. Report what it created and mention the title I can change it to. Do not modify any other project files.'
|
|
8472
|
+
},
|
|
8473
|
+
// The analysis comes first (upload plan AP7): the report, not the model,
|
|
8474
|
+
// says what would be uploaded, how large it is and what blocks it, and the
|
|
8475
|
+
// rules for acting on it are in AGENTFUL_CLOUD.md. Two things the agent's
|
|
8476
|
+
// shell tool forces on this template: `--summary`, because the tool cuts
|
|
8477
|
+
// output after 2,000 lines or 50 KB and the full report lists every file;
|
|
8478
|
+
// and an explicit timeout, because the tool ends a command after two
|
|
8479
|
+
// minutes by default and a cloud build takes longer (engine 1.18.32).
|
|
8480
|
+
push: {
|
|
8481
|
+
description: `${brand.displayName}: check, deploy and get a preview URL`,
|
|
8482
|
+
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.
|
|
8483
|
+
|
|
8484
|
+
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.
|
|
8485
|
+
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. 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.
|
|
8486
|
+
3. After a change I approved, run the analysis again.
|
|
8487
|
+
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.
|
|
8488
|
+
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.
|
|
8489
|
+
|
|
8490
|
+
Apart from a change I approved in step 2, do not modify project files.`
|
|
8491
|
+
},
|
|
8492
|
+
"build-status": {
|
|
8493
|
+
description: `${brand.displayName}: show the last cloud build result`,
|
|
8494
|
+
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
|
|
8495
|
+
},
|
|
8496
|
+
backend: {
|
|
8497
|
+
description: `${brand.displayName}: open the Backend tab (managed DB + server actions)`,
|
|
8498
|
+
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
|
|
8499
|
+
},
|
|
8500
|
+
preview: {
|
|
8501
|
+
description: `${brand.displayName}: open the live preview in the browser`,
|
|
8502
|
+
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
|
|
8503
|
+
},
|
|
8504
|
+
publish: {
|
|
8505
|
+
description: `${brand.displayName}: publish on a public subdomain`,
|
|
8506
|
+
template: "Ask me for the subdomain if I did not provide one in $ARGUMENTS, then run `agentful publish <subdomain>` from the project root using the bash tool and report the public URL. " + NEEDS_A_PUSH
|
|
8507
|
+
},
|
|
8508
|
+
share: {
|
|
8509
|
+
description: `${brand.displayName}: make the live preview public (or private again)`,
|
|
8510
|
+
template: "Run `agentful share` from the project root using the bash tool (add `--private` if $ARGUMENTS says private) and report the resulting visibility and URL. " + NEEDS_A_PUSH
|
|
8511
|
+
},
|
|
8512
|
+
status: {
|
|
8513
|
+
description: `${brand.displayName}: show the linked project and account`,
|
|
8514
|
+
template: "Run `agentful whoami` using the bash tool. Then read .agentful/project.json and report the linked project title and id, plus the preview URL https://preview-<projectId>.agentful.page/. If the file does not exist, say that this directory is not linked yet and that `/setup` creates the link."
|
|
8515
|
+
}
|
|
8516
|
+
};
|
|
8517
|
+
function commandMarkdown(name) {
|
|
8518
|
+
const cmd = SLASH_COMMANDS[name];
|
|
8519
|
+
const description = JSON.stringify(cmd.description);
|
|
8520
|
+
return `---
|
|
8521
|
+
description: ${description}
|
|
8522
|
+
agent: ${cmd.agent ?? "agentful-build"}
|
|
8523
|
+
---
|
|
8524
|
+
|
|
8525
|
+
${cmd.template}
|
|
8526
|
+
`;
|
|
8527
|
+
}
|
|
8528
|
+
|
|
8529
|
+
// src/lib/tools.ts
|
|
8530
|
+
var import_node_fs13 = require("fs");
|
|
8531
|
+
var import_node_path15 = require("path");
|
|
8532
|
+
function assetsDir() {
|
|
8533
|
+
const here = (0, import_node_path15.dirname)(process.argv[1] || "");
|
|
8534
|
+
for (const candidate of [(0, import_node_path15.join)(here, "..", "assets"), (0, import_node_path15.join)(here, "assets")]) {
|
|
8535
|
+
if ((0, import_node_fs13.existsSync)((0, import_node_path15.join)(candidate, "tools", "imagegen.ts"))) return candidate;
|
|
8536
|
+
}
|
|
8537
|
+
return null;
|
|
8538
|
+
}
|
|
8539
|
+
function installEngineTools(configDir2) {
|
|
8540
|
+
const assets = assetsDir();
|
|
8541
|
+
if (!assets) return false;
|
|
8542
|
+
const target = (0, import_node_path15.join)(configDir2, "tools");
|
|
8543
|
+
(0, import_node_fs13.mkdirSync)(target, { recursive: true });
|
|
8544
|
+
try {
|
|
8545
|
+
(0, import_node_fs13.cpSync)((0, import_node_path15.join)(assets, "tools"), target, { recursive: true });
|
|
8546
|
+
return true;
|
|
8547
|
+
} catch {
|
|
8548
|
+
return false;
|
|
8549
|
+
}
|
|
8550
|
+
}
|
|
8551
|
+
|
|
8321
8552
|
// src/lib/engineConfig.ts
|
|
8322
8553
|
var PROVIDER_ID = "agentful";
|
|
8323
8554
|
var DISABLED_ENGINE_PLUGINS = {
|
|
@@ -8555,18 +8786,20 @@ var SCAFFOLD_BY_FRAMEWORK = {
|
|
|
8555
8786
|
// cra/nuxt get no scaffold skill: the react/vue skills are Vite-specific
|
|
8556
8787
|
// and would teach the wrong shape — the template contract still applies.
|
|
8557
8788
|
};
|
|
8558
|
-
function
|
|
8789
|
+
function dependencies(rootDir) {
|
|
8559
8790
|
try {
|
|
8560
8791
|
const pkg = JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path17.join)(rootDir, "package.json"), "utf8"));
|
|
8561
|
-
return
|
|
8792
|
+
return { ...pkg.dependencies, ...pkg.devDependencies };
|
|
8562
8793
|
} catch {
|
|
8563
|
-
return
|
|
8794
|
+
return {};
|
|
8564
8795
|
}
|
|
8565
8796
|
}
|
|
8566
8797
|
function selectSkills(framework, rootDir) {
|
|
8567
8798
|
const names = [CONTRACT_SKILL];
|
|
8568
8799
|
if (framework === "vite") {
|
|
8569
|
-
|
|
8800
|
+
const deps = dependencies(rootDir);
|
|
8801
|
+
if (deps.vue) names.push("vue-scaffold");
|
|
8802
|
+
else if (deps.react) names.push("react-scaffold");
|
|
8570
8803
|
} else {
|
|
8571
8804
|
const scaffold = SCAFFOLD_BY_FRAMEWORK[framework];
|
|
8572
8805
|
if (scaffold) names.push(scaffold);
|
|
@@ -9895,7 +10128,7 @@ program2.command("login").description("Sign in to your Agentful account (device
|
|
|
9895
10128
|
program2.command("logout").description("Remove the stored credentials").action(run(logoutCommand));
|
|
9896
10129
|
program2.command("whoami").description("Show the signed-in account").action(run(whoamiCommand));
|
|
9897
10130
|
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)));
|
|
9898
|
-
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").option("--dry-run", "analyse only: what would be uploaded, how large, and what would block it \u2014 no sign-in, no project, no upload").option("--json", "with --dry-run: print the analysis as JSON (for scripts and agents)").action(run((opts) => pushCommand(opts)));
|
|
10131
|
+
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").option("--dry-run", "analyse only: what would be uploaded, how large, and what would block it \u2014 no sign-in, no project, no upload").option("--json", "with --dry-run: print the analysis as JSON (for scripts and agents)").option("--summary", "with --dry-run --json: totals and findings without the list of every file").action(run((opts) => pushCommand(opts)));
|
|
9899
10132
|
program2.command("build-status").description("Show the cloud's record of the last build (the real error on failures)").action(run(buildStatusCommand));
|
|
9900
10133
|
program2.command("backend").description("Open this project's Backend tab (managed DB + server actions) in the browser").action(run(backendCommand));
|
|
9901
10134
|
program2.command("open").description("Open the live preview in the browser").action(run(openCommand));
|