deployai 0.1.0-beta.6 → 0.1.0-beta.8
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 +1 -1
- package/dist/index.js +108 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Node 20 or newer. No other setup: the CLI talks to https://deployai.co.il.
|
|
|
38
38
|
|
|
39
39
|
| Command | What it does |
|
|
40
40
|
|---------|--------------|
|
|
41
|
-
| `deployai init` | Creates `DEPLOYAI.md` (rules for the AI agent) and `.deployai/project.json`. Never edits your code and does not link a project (use `link`). `--force` overwrites `DEPLOYAI.md
|
|
41
|
+
| `deployai init` | Creates `DEPLOYAI.md` (rules for the AI agent: the stack to build with, what to avoid, how to keep existing data), adds one line pointing to it in `AGENTS.md` and `CLAUDE.md`, and `.deployai/project.json`. Run it first in a new project, even an empty folder. Never edits your code and does not link a project (use `link`). `--force` overwrites `DEPLOYAI.md`, `--no-agent-files` leaves `AGENTS.md` and `CLAUDE.md` alone. |
|
|
42
42
|
| `deployai inspect` | Shows framework, package manager, language, database, storage and the number of env files (values are never read). `--json` for machine output. |
|
|
43
43
|
| `deployai check` | Lists blockers and warnings with file and line. It answers only whether the project can run on DeployAI. More below. |
|
|
44
44
|
| `deployai login` | Logs in through the browser (device code). The token lasts 30 days and is stored in `~/.deployai/config.json` with the API address that issued it; it is never sent to another address. |
|
package/dist/index.js
CHANGED
|
@@ -21365,7 +21365,7 @@ var CLI_MAP_NODES = [
|
|
|
21365
21365
|
n("cmd-start", "cli", "start <id>", "\u05DE\u05DB\u05D9\u05DF \u05D0\u05EA \u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05DC\u05E4\u05D9 \u05DB\u05DC \u05D4\u05D1\u05D7\u05D9\u05E8\u05D5\u05EA: \u05EA\u05D9\u05E7\u05D9\u05D9\u05D4, \u05D3\u05D5\u05D2\u05DE\u05D4 \u05D5\u05D4\u05EA\u05E7\u05E0\u05D4, \u05E7\u05D5\u05D1\u05E5 \u05D4\u05E4\u05E8\u05D8\u05D9\u05DD \u05D5\u05D7\u05D9\u05D1\u05D5\u05E8 \u05DC\u05D0\u05EA\u05E8. \u05DE\u05D3\u05E4\u05D9\u05E1 \u05DC\u05E1\u05D5\u05DB\u05DF \u05D0\u05EA \u05D4\u05D8\u05E7\u05E1\u05D8 \u05D5\u05D0\u05EA \u05D4\u05E4\u05E7\u05D5\u05D3\u05D5\u05EA.", "Prepares the folder with every choice: folder, sample and install, the details file and the site link. Prints the text and the commands for the agent."),
|
|
21366
21366
|
n("cmd-samples", "cli", "samples [key]", "\u05E8\u05E9\u05D9\u05DE\u05EA \u05D4\u05D3\u05D5\u05D2\u05DE\u05D0\u05D5\u05EA, \u05D0\u05D5 \u05D4\u05D5\u05E8\u05D3\u05D4 \u05E9\u05DC \u05D0\u05D7\u05EA.", "Lists the samples, or downloads one."),
|
|
21367
21367
|
n("cmd-check", "cli", "check", "\u05D4\u05D0\u05DD \u05D4\u05E4\u05E8\u05D5\u05D9\u05E7\u05D8 \u05D9\u05DB\u05D5\u05DC \u05DC\u05E8\u05D5\u05E5 \u05D0\u05E6\u05DC\u05E0\u05D5: \u05D7\u05D5\u05E1\u05DE\u05D9\u05DD \u05D5\u05D0\u05D6\u05D4\u05E8\u05D5\u05EA, \u05E2\u05DD \u05E4\u05E8\u05D5\u05DE\u05E4\u05D8 \u05EA\u05D9\u05E7\u05D5\u05DF.", "Can the project run on our hosting: blockers and warnings, with a fix prompt."),
|
|
21368
|
-
n("cmd-init", "cli", "init", "\u05D9\u05D5\u05E6\u05E8 DEPLOYAI.md \u05D5 .deployai/project.json.", "Creates DEPLOYAI.md and .deployai/project.json."),
|
|
21368
|
+
n("cmd-init", "cli", "init", "\u05D9\u05D5\u05E6\u05E8 DEPLOYAI.md \u05E2\u05DD \u05D4\u05DB\u05DC\u05DC\u05D9\u05DD \u05DC\u05E1\u05D5\u05DB\u05DF, \u05E9\u05D5\u05E8\u05D4 \u05D0\u05DC\u05D9\u05D5 \u05D1 AGENTS.md \u05D5 CLAUDE.md, \u05D5 .deployai/project.json. \u05E8\u05D0\u05E9\u05D5\u05DF \u05D1\u05E4\u05E8\u05D5\u05D9\u05E7\u05D8 \u05D7\u05D3\u05E9.", "Creates DEPLOYAI.md with the agent rules, a line to it in AGENTS.md and CLAUDE.md, and .deployai/project.json. First in a new project."),
|
|
21369
21369
|
n("cmd-inspect", "cli", "inspect", "\u05DE\u05D4 \u05D6\u05D5\u05D4\u05D4 \u05D1\u05E4\u05E8\u05D5\u05D9\u05E7\u05D8: \u05DE\u05E1\u05D2\u05E8\u05EA, \u05E9\u05E4\u05D4, \u05DE\u05E1\u05D3 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD.", "What the project is: framework, language, database."),
|
|
21370
21370
|
n("cmd-login", "cli", "login", "\u05DB\u05E0\u05D9\u05E1\u05D4 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF, \u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8 \u05DE\u05D0\u05E9\u05E8.", "Login in the browser, the owner approves."),
|
|
21371
21371
|
n("cmd-logout", "cli", "logout", "\u05DE\u05D1\u05D8\u05DC \u05D0\u05EA \u05D4\u05D8\u05D5\u05E7\u05DF \u05D5\u05D9\u05D5\u05E6\u05D0 \u05DE\u05D4\u05D7\u05E9\u05D1\u05D5\u05DF \u05D1\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4.", "Cancels the token and logs out on this computer."),
|
|
@@ -21643,6 +21643,26 @@ var SPACES = {
|
|
|
21643
21643
|
test: build("test", { ...CLOUDFLARE_SPACES.prod, kvNamespaceId: "", sitesZoneId: null, backupBucket: null, toolsWorkerUrl: "" }, { ...SPACE_ADDRESSES.prod, appUrl: "http://localhost:3000", siteUrl: "http://localhost:3000", trustedOrigins: [], storage: "local" })
|
|
21644
21644
|
};
|
|
21645
21645
|
|
|
21646
|
+
// ../shared/src/agent-rules.ts
|
|
21647
|
+
var BUILD_WITH = [
|
|
21648
|
+
`Frameworks: ${SUPPORTED_FRAMEWORKS.map((f) => f.name).join(", ")}. In beta: ${BETA_FRAMEWORKS.map((f) => f.name).join(", ")} (Next.js through the OpenNext Cloudflare adapter).`,
|
|
21649
|
+
"Database: Cloudflare D1 (SQLite), through Drizzle with drizzle-orm/d1 or Prisma with the D1 adapter.",
|
|
21650
|
+
"Uploaded files and images: Cloudflare R2 (object storage), never the local disk.",
|
|
21651
|
+
"Settings and secrets: environment variables, set with: npx deployai@latest env set <key>",
|
|
21652
|
+
"Images: resize at build time or serve them as they are; no native image modules at runtime.",
|
|
21653
|
+
"Passwords: bcryptjs or Web Crypto, never native bcrypt.",
|
|
21654
|
+
"Server code runs per request: no long-running processes, background servers or child processes."
|
|
21655
|
+
];
|
|
21656
|
+
var KEEP_DATA_RULES = [
|
|
21657
|
+
"Moving to DeployAI changes where data lives. It never moves the data by itself. Before you switch any of these, save a copy inside the project and tell the user, in simple words, what was saved and where:",
|
|
21658
|
+
"- Database (Postgres, MySQL, MongoDB, a SQLite file): export it to a file (pg_dump, mysqldump, mongoexport, sqlite3 .dump), so it can be imported into D1 later.",
|
|
21659
|
+
"- Uploaded files and images on the local disk or another storage service: keep them in a folder (download them first if they are on another service), so they can be uploaded to R2 later.",
|
|
21660
|
+
"- User accounts and passwords: keep existing password hashes working (bcryptjs reads bcrypt hashes), so no one has to reset.",
|
|
21661
|
+
"- Sessions and cache (Redis, memory): these can be lost, and users may have to log in again. Say so.",
|
|
21662
|
+
"Never delete the old database, files or storage service."
|
|
21663
|
+
];
|
|
21664
|
+
var AGENT_POINTER = "Read DEPLOYAI.md before you write code, change the plan or add a dependency: this project is published with DeployAI.";
|
|
21665
|
+
|
|
21646
21666
|
// src/config.ts
|
|
21647
21667
|
import { randomUUID } from "crypto";
|
|
21648
21668
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -21790,6 +21810,7 @@ var M = {
|
|
|
21790
21810
|
startInstalled: "Installed its packages (npm install).",
|
|
21791
21811
|
startBrief: "Wrote the owner's details to {file} (kept out of git and never uploaded).",
|
|
21792
21812
|
startLinked: 'Linked this folder to the site "{name}".',
|
|
21813
|
+
startRules: "Wrote the rules for your agent to DEPLOYAI.md (never uploaded).",
|
|
21793
21814
|
startRelinked: 'Linked this folder to the site "{name}" instead of the site it was linked to.',
|
|
21794
21815
|
statusLine: "Status: {s}",
|
|
21795
21816
|
ready: "ready",
|
|
@@ -21803,6 +21824,7 @@ var M = {
|
|
|
21803
21824
|
pasteFix: " Paste the prompt below into your AI editor, then run: npx deployai@latest check",
|
|
21804
21825
|
copied: " (copied to clipboard)",
|
|
21805
21826
|
runDeploy: ' Run: npx deployai@latest deploy -m "<message>"',
|
|
21827
|
+
initHint: " So your agent follows the DeployAI rules, run: npx deployai@latest init",
|
|
21806
21828
|
deployTitle: "DeployAI deploy",
|
|
21807
21829
|
guestTitle: "DeployAI deploy (no account)",
|
|
21808
21830
|
uploading: "Uploading...",
|
|
@@ -21959,6 +21981,7 @@ var M = {
|
|
|
21959
21981
|
startInstalled: "\u05D4\u05D7\u05D1\u05D9\u05DC\u05D5\u05EA \u05E9\u05DC\u05D4 \u05D4\u05D5\u05EA\u05E7\u05E0\u05D5 (npm install).",
|
|
21960
21982
|
startBrief: "\u05D4\u05E4\u05E8\u05D8\u05D9\u05DD \u05E9\u05DC \u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8 \u05E0\u05DB\u05EA\u05D1\u05D5 \u05DC {file} (\u05DC\u05D0 \u05E0\u05DB\u05E0\u05E1\u05D9\u05DD \u05DC\u05BEgit \u05D5\u05DC\u05D0 \u05E2\u05D5\u05DC\u05D9\u05DD \u05DC\u05D0\u05EA\u05E8).",
|
|
21961
21983
|
startLinked: '\u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D7\u05D5\u05D1\u05E8\u05D4 \u05DC\u05D0\u05EA\u05E8 "{name}".',
|
|
21984
|
+
startRules: "\u05D4\u05DB\u05DC\u05DC\u05D9\u05DD \u05DC\u05E1\u05D5\u05DB\u05DF \u05E0\u05DB\u05EA\u05D1\u05D5 \u05DC DEPLOYAI.md (\u05DC\u05D0 \u05E2\u05D5\u05DC\u05D9\u05DD \u05DC\u05D0\u05EA\u05E8).",
|
|
21962
21985
|
startRelinked: '\u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D7\u05D5\u05D1\u05E8\u05D4 \u05DC\u05D0\u05EA\u05E8 "{name}" \u05D1\u05DE\u05E7\u05D5\u05DD \u05D4\u05D0\u05EA\u05E8 \u05E9\u05D4\u05D9\u05D9\u05EA\u05D4 \u05DE\u05D7\u05D5\u05D1\u05E8\u05EA \u05D0\u05DC\u05D9\u05D5.',
|
|
21963
21986
|
statusLine: "\u05DE\u05E6\u05D1: {s}",
|
|
21964
21987
|
ready: "\u05DE\u05D5\u05DB\u05DF \u05DC\u05E2\u05DC\u05D5\u05EA",
|
|
@@ -21972,6 +21995,7 @@ var M = {
|
|
|
21972
21995
|
pasteFix: " \u05D4\u05D3\u05D1\u05D9\u05E7\u05D5 \u05D0\u05EA \u05D4\u05E4\u05E8\u05D5\u05DE\u05E4\u05D8 \u05E9\u05DC\u05DE\u05D8\u05D4 \u05DC\u05E1\u05D5\u05DB\u05DF, \u05D5\u05D0\u05D6 \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest check",
|
|
21973
21996
|
copied: " (\u05D4\u05D5\u05E2\u05EA\u05E7)",
|
|
21974
21997
|
runDeploy: ' \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest deploy -m "<message>"',
|
|
21998
|
+
initHint: " \u05DB\u05D3\u05D9 \u05E9\u05D4\u05E1\u05D5\u05DB\u05DF \u05D9\u05E2\u05D1\u05D5\u05D3 \u05DC\u05E4\u05D9 \u05D4\u05DB\u05DC\u05DC\u05D9\u05DD \u05E9\u05DC DeployAI, \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest init",
|
|
21975
21999
|
deployTitle: "DeployAI deploy",
|
|
21976
22000
|
guestTitle: "DeployAI deploy (\u05D1\u05DC\u05D9 \u05D7\u05E9\u05D1\u05D5\u05DF)",
|
|
21977
22001
|
uploading: "\u05DE\u05E2\u05DC\u05D9\u05DD...",
|
|
@@ -22132,7 +22156,7 @@ function messages(root) {
|
|
|
22132
22156
|
}
|
|
22133
22157
|
|
|
22134
22158
|
// src/version.ts
|
|
22135
|
-
var CLI_VERSION = "0.1.0-beta.
|
|
22159
|
+
var CLI_VERSION = "0.1.0-beta.8";
|
|
22136
22160
|
|
|
22137
22161
|
// src/api.ts
|
|
22138
22162
|
function apiContext(apiFlag) {
|
|
@@ -22361,7 +22385,7 @@ async function sendTelemetryEvent(ctx, event) {
|
|
|
22361
22385
|
}
|
|
22362
22386
|
|
|
22363
22387
|
// src/commands/init.ts
|
|
22364
|
-
import { existsSync as existsSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
22388
|
+
import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
22365
22389
|
import { join as join5 } from "path";
|
|
22366
22390
|
|
|
22367
22391
|
// src/analyze.ts
|
|
@@ -22529,6 +22553,7 @@ function planUpload(root) {
|
|
|
22529
22553
|
}
|
|
22530
22554
|
|
|
22531
22555
|
// src/analyze.ts
|
|
22556
|
+
var INIT_FILES = /* @__PURE__ */ new Set(["DEPLOYAI.md", "AGENTS.md", "CLAUDE.md"]);
|
|
22532
22557
|
var CODE_EXT = /\.(js|jsx|ts|tsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
22533
22558
|
var SECRET_SCAN_EXT = /\.(js|jsx|ts|tsx|mjs|cjs|mts|cts|vue|svelte|astro|json|ya?ml|toml|html|prisma)$/;
|
|
22534
22559
|
var LOCKFILES = /* @__PURE__ */ new Set(["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"]);
|
|
@@ -22886,7 +22911,7 @@ function analyzeProject(root) {
|
|
|
22886
22911
|
}
|
|
22887
22912
|
const otherStack = detectOtherStack(files.map((f) => f.rel));
|
|
22888
22913
|
if (otherStack) add({ code: "other_stack", severity: "blocker", detail: ` ${otherStack.name}` });
|
|
22889
|
-
const empty = !files.some((f) => !f.rel.startsWith(".deployai/") && f.rel
|
|
22914
|
+
const empty = !files.some((f) => !f.rel.startsWith(".deployai/") && !INIT_FILES.has(f.rel) && !isEnvFile(f.rel.split("/").pop() ?? ""));
|
|
22890
22915
|
if (empty) add({ code: "no_files", severity: "blocker" });
|
|
22891
22916
|
if (framework.id === "unknown" && !otherStack && !empty) {
|
|
22892
22917
|
add({ code: "unknown_framework", severity: "warning", detail: framework.flavor ? ` (looks like ${framework.flavor})` : "" });
|
|
@@ -22984,13 +23009,34 @@ This project is published with DeployAI.
|
|
|
22984
23009
|
|
|
22985
23010
|
Always explain to the user in simple words, in the language they write to you in. The user may not read English.
|
|
22986
23011
|
|
|
22987
|
-
|
|
23012
|
+
When you install or set something up, say what it does for the site, not the package name. Say "installing the site runtime" or "setting up a local test database", not "installing the Cloudflare adapter" or "installing wrangler".
|
|
23013
|
+
|
|
23014
|
+
Before you write code or change the plan, compare it with these rules. If something in it does not fit, say what and propose the change.
|
|
23015
|
+
|
|
23016
|
+
## Build with
|
|
23017
|
+
|
|
23018
|
+
${BUILD_WITH.map((l) => `- ${l}`).join("\n")}
|
|
23019
|
+
|
|
23020
|
+
To start from working code, see the samples: npx deployai@latest samples
|
|
23021
|
+
|
|
23022
|
+
## Do not add
|
|
23023
|
+
|
|
22988
23024
|
- local file system writes
|
|
22989
23025
|
- database drivers DeployAI does not support (see: npx deployai@latest inspect)
|
|
22990
23026
|
- long-running processes or background servers
|
|
22991
23027
|
- native binary modules
|
|
22992
23028
|
- DeployAI or any cloud credentials in source code
|
|
22993
23029
|
|
|
23030
|
+
## Do not run
|
|
23031
|
+
|
|
23032
|
+
- wrangler commands that need a Cloudflare account (login, deploy, d1 create, r2 bucket create). Wrangler is installed only for local development. The user does not need a Cloudflare account: DeployAI creates the database and storage and publishes the site, with: npx deployai@latest deploy
|
|
23033
|
+
|
|
23034
|
+
## Keep existing data
|
|
23035
|
+
|
|
23036
|
+
${KEEP_DATA_RULES.join("\n")}
|
|
23037
|
+
|
|
23038
|
+
## Check
|
|
23039
|
+
|
|
22994
23040
|
Before adding a dependency or a new server feature, run: npx deployai@latest check
|
|
22995
23041
|
Ask the developer before removing any existing functionality.
|
|
22996
23042
|
|
|
@@ -22998,9 +23044,11 @@ Files:
|
|
|
22998
23044
|
- .deployai/project.json: project id and settings (safe to commit)
|
|
22999
23045
|
- .deployai/last-check.json: latest check result (not committed)
|
|
23000
23046
|
`;
|
|
23047
|
+
var AGENT_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
23001
23048
|
function runInit(root, opts = {}) {
|
|
23002
23049
|
const created = [];
|
|
23003
23050
|
const kept = [];
|
|
23051
|
+
const updated = [];
|
|
23004
23052
|
const md = join5(root, "DEPLOYAI.md");
|
|
23005
23053
|
if (existsSync5(md) && !opts.force) {
|
|
23006
23054
|
kept.push("DEPLOYAI.md");
|
|
@@ -23008,20 +23056,35 @@ function runInit(root, opts = {}) {
|
|
|
23008
23056
|
writeFileSync3(md, DEPLOYAI_MD);
|
|
23009
23057
|
created.push("DEPLOYAI.md");
|
|
23010
23058
|
}
|
|
23059
|
+
if (opts.agentFiles !== false) {
|
|
23060
|
+
for (const name of AGENT_FILES) {
|
|
23061
|
+
const file2 = join5(root, name);
|
|
23062
|
+
const text = existsSync5(file2) ? readFileSync5(file2, "utf8") : null;
|
|
23063
|
+
if (text === null) {
|
|
23064
|
+
writeFileSync3(file2, `${AGENT_POINTER}
|
|
23065
|
+
`);
|
|
23066
|
+
created.push(name);
|
|
23067
|
+
} else if (text.includes("DEPLOYAI.md")) {
|
|
23068
|
+
kept.push(name);
|
|
23069
|
+
} else {
|
|
23070
|
+
const eol = text.includes("\r\n") ? "\r\n" : "\n";
|
|
23071
|
+
const gap = !text.trim() ? "" : text.endsWith("\n") ? eol : eol + eol;
|
|
23072
|
+
appendFileSync(file2, `${gap}${AGENT_POINTER}${eol}`);
|
|
23073
|
+
updated.push(name);
|
|
23074
|
+
}
|
|
23075
|
+
}
|
|
23076
|
+
}
|
|
23011
23077
|
ensureDeployaiDir(root);
|
|
23012
23078
|
const existing = readProject(root);
|
|
23079
|
+
const framework = existing?.framework ?? analyzeProject(root).inspect.framework.id;
|
|
23013
23080
|
if (existing) {
|
|
23014
23081
|
kept.push(".deployai/project.json");
|
|
23015
23082
|
} else {
|
|
23016
|
-
|
|
23017
|
-
writeProject(root, {
|
|
23018
|
-
projectId: null,
|
|
23019
|
-
framework: analysis.inspect.framework.id,
|
|
23020
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23021
|
-
});
|
|
23083
|
+
writeProject(root, { projectId: null, framework, createdAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
23022
23084
|
created.push(".deployai/project.json");
|
|
23023
23085
|
}
|
|
23024
|
-
|
|
23086
|
+
const hasCode = existsSync5(join5(root, "package.json")) || framework !== "unknown";
|
|
23087
|
+
return { created, kept, updated, hasCode };
|
|
23025
23088
|
}
|
|
23026
23089
|
function initCommand(root, opts) {
|
|
23027
23090
|
const res = runInit(root, opts);
|
|
@@ -23031,6 +23094,7 @@ function initCommand(root, opts) {
|
|
|
23031
23094
|
out(
|
|
23032
23095
|
rows([
|
|
23033
23096
|
...res.created.map((f) => ["Created", f]),
|
|
23097
|
+
...res.updated.map((f) => ["Added a line", `${f} (read DEPLOYAI.md)`]),
|
|
23034
23098
|
...res.kept.map((f) => ["Kept", f]),
|
|
23035
23099
|
["Guard", ".deployai/last-check.json (git ignored)"],
|
|
23036
23100
|
["Linked project", project?.projectId ?? "none yet"]
|
|
@@ -23038,12 +23102,18 @@ function initCommand(root, opts) {
|
|
|
23038
23102
|
);
|
|
23039
23103
|
out();
|
|
23040
23104
|
out("Next step");
|
|
23041
|
-
|
|
23105
|
+
if (res.hasCode) {
|
|
23106
|
+
out(" Run: npx deployai@latest check");
|
|
23107
|
+
} else {
|
|
23108
|
+
out(" Start from a sample: npx deployai@latest samples");
|
|
23109
|
+
out(" Or tell your agent what to build, or to review your plan. It follows DEPLOYAI.md.");
|
|
23110
|
+
}
|
|
23042
23111
|
if (!project?.projectId) out(" Then: npx deployai@latest login, npx deployai@latest link");
|
|
23043
23112
|
}
|
|
23044
23113
|
|
|
23045
23114
|
// src/commands/check.ts
|
|
23046
|
-
import { writeFileSync as writeFileSync4 } from "fs";
|
|
23115
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
23116
|
+
import { join as join6 } from "path";
|
|
23047
23117
|
|
|
23048
23118
|
// src/prompt.ts
|
|
23049
23119
|
var PROMPT_RULES = [
|
|
@@ -23053,8 +23123,10 @@ var PROMPT_RULES = [
|
|
|
23053
23123
|
"Keep the project runnable outside DeployAI.",
|
|
23054
23124
|
"Never add credentials to source code.",
|
|
23055
23125
|
"Explain every step to the user in simple words, in the language they write to you in.",
|
|
23056
|
-
"For the database, use D1 as shown in the DeployAI CRUD sample."
|
|
23126
|
+
"For the database, use D1 as shown in the DeployAI CRUD sample.",
|
|
23127
|
+
"Follow DEPLOYAI.md for every future change. If it is missing, run: npx deployai@latest init"
|
|
23057
23128
|
];
|
|
23129
|
+
var DATA_CODES = /* @__PURE__ */ new Set(["fs_write", "unsupported_db_postgres", "unsupported_db_mysql", "unsupported_db_mongodb", "unsupported_db_sqlite_file", "native_module_bcrypt"]);
|
|
23058
23130
|
var MAX_LOCATIONS = 3;
|
|
23059
23131
|
function locList(items) {
|
|
23060
23132
|
const locs = [...new Set(items.map(locationOf).filter(Boolean))];
|
|
@@ -23093,6 +23165,11 @@ function buildPrompt(analysis) {
|
|
|
23093
23165
|
if (def) lines.push(`- ${def.fixForAgent}`);
|
|
23094
23166
|
}
|
|
23095
23167
|
lines.push("");
|
|
23168
|
+
if (blockerGroups.some((g) => DATA_CODES.has(g.code))) {
|
|
23169
|
+
lines.push("Keep existing data:");
|
|
23170
|
+
lines.push(...KEEP_DATA_RULES);
|
|
23171
|
+
lines.push("");
|
|
23172
|
+
}
|
|
23096
23173
|
lines.push("Rules:");
|
|
23097
23174
|
for (const r of PROMPT_RULES) lines.push(`- ${r}`);
|
|
23098
23175
|
lines.push("");
|
|
@@ -23242,6 +23319,7 @@ async function runCheck(root, ctx, opts = {}) {
|
|
|
23242
23319
|
} else {
|
|
23243
23320
|
out(t("runDeploy"));
|
|
23244
23321
|
}
|
|
23322
|
+
if (!existsSync6(join6(root, "DEPLOYAI.md"))) out(t("initHint"));
|
|
23245
23323
|
}
|
|
23246
23324
|
await telemetry;
|
|
23247
23325
|
return a;
|
|
@@ -23455,7 +23533,7 @@ async function linkCommand(root, ctx, target, opts) {
|
|
|
23455
23533
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
23456
23534
|
|
|
23457
23535
|
// src/tar.ts
|
|
23458
|
-
import { readFileSync as
|
|
23536
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
23459
23537
|
import { gzipSync } from "zlib";
|
|
23460
23538
|
var BLOCK = 512;
|
|
23461
23539
|
function writeString(buf, offset, length, value) {
|
|
@@ -23539,7 +23617,7 @@ function packFiles(files) {
|
|
|
23539
23617
|
return createTarGz(
|
|
23540
23618
|
files.map((f) => ({
|
|
23541
23619
|
name: f.rel,
|
|
23542
|
-
data:
|
|
23620
|
+
data: readFileSync6(f.abs),
|
|
23543
23621
|
mtimeMs: f.mtimeMs,
|
|
23544
23622
|
mode: f.mode & 64 ? 493 : 420
|
|
23545
23623
|
}))
|
|
@@ -23742,8 +23820,8 @@ async function claimCommand(root, ctx, opts) {
|
|
|
23742
23820
|
|
|
23743
23821
|
// src/commands/samples.ts
|
|
23744
23822
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
23745
|
-
import { existsSync as
|
|
23746
|
-
import { dirname, join as
|
|
23823
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
23824
|
+
import { dirname, join as join7, relative, resolve, sep } from "path";
|
|
23747
23825
|
import { gunzipSync } from "zlib";
|
|
23748
23826
|
var SAMPLES = [
|
|
23749
23827
|
{ key: "landing", title: "Landing page: a full one-page site with WhatsApp sign-up", stack: "static HTML and CSS" },
|
|
@@ -23754,7 +23832,7 @@ var SAMPLES = [
|
|
|
23754
23832
|
{ key: "admin", title: "Back office with login: dashboard, orders, stock, customers", stack: "Astro on Workers, D1" }
|
|
23755
23833
|
];
|
|
23756
23834
|
var MAX_BYTES = 20 * 1024 * 1024;
|
|
23757
|
-
var IGNORED = /* @__PURE__ */ new Set([".git", ".DS_Store", "Thumbs.db", ".deployai"]);
|
|
23835
|
+
var IGNORED = /* @__PURE__ */ new Set([".git", ".DS_Store", "Thumbs.db", ".deployai", "DEPLOYAI.md", "AGENTS.md", "CLAUDE.md"]);
|
|
23758
23836
|
function listSamples(apiUrl) {
|
|
23759
23837
|
out("DeployAI samples");
|
|
23760
23838
|
out("");
|
|
@@ -23764,7 +23842,7 @@ function listSamples(apiUrl) {
|
|
|
23764
23842
|
out(`See them live: ${apiUrl}/samples`);
|
|
23765
23843
|
}
|
|
23766
23844
|
function filesIn(dir) {
|
|
23767
|
-
return
|
|
23845
|
+
return existsSync7(dir) ? readdirSync3(dir).filter((f) => !IGNORED.has(f)) : [];
|
|
23768
23846
|
}
|
|
23769
23847
|
function freeFolder(cwd, key) {
|
|
23770
23848
|
for (let n2 = 1; ; n2++) {
|
|
@@ -23847,7 +23925,7 @@ async function samplesCommand(cwd, ctx, key, opts = {}) {
|
|
|
23847
23925
|
}
|
|
23848
23926
|
const written = await downloadSample(ctx, sample.key, root);
|
|
23849
23927
|
const base = resolve(root);
|
|
23850
|
-
const hasPackage =
|
|
23928
|
+
const hasPackage = existsSync7(join7(base, "package.json"));
|
|
23851
23929
|
out(base === resolve(cwd) ? `Downloaded the ${sample.key} sample: ${written} files.` : `Downloaded the ${sample.key} sample into the new folder ${relative(cwd, base)}: ${written} files. Work in that folder from now on.`);
|
|
23852
23930
|
out("");
|
|
23853
23931
|
const t = messages(base);
|
|
@@ -23992,8 +24070,8 @@ async function statusCommand(root, ctx) {
|
|
|
23992
24070
|
|
|
23993
24071
|
// src/commands/start.ts
|
|
23994
24072
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
23995
|
-
import { existsSync as
|
|
23996
|
-
import { join as
|
|
24073
|
+
import { existsSync as existsSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
24074
|
+
import { join as join8, relative as relative2, resolve as resolve2 } from "path";
|
|
23997
24075
|
var REASONS = { start_not_found: "startNotFound", start_expired: "startExpired", start_used_up: "startUsedUp" };
|
|
23998
24076
|
var reason = (code) => messages(process.cwd())(REASONS[code] ?? "startNotFound");
|
|
23999
24077
|
async function fetchStart(ctx, id) {
|
|
@@ -24031,19 +24109,20 @@ async function startCommand(cwd, ctx, id, opts = {}) {
|
|
|
24031
24109
|
if (sample && !sameSite) {
|
|
24032
24110
|
const written = await downloadSample(ctx, sample.key, root);
|
|
24033
24111
|
done.push(t("startDownloaded", { key: sample.key, n: written }));
|
|
24034
|
-
if (
|
|
24112
|
+
if (existsSync8(join8(root, "package.json"))) {
|
|
24035
24113
|
if (opts.install !== false && install(root)) done.push(t("startInstalled"));
|
|
24036
24114
|
else steps.unshift({ cmd: "npm install", say: "Installs the sample's packages." });
|
|
24037
24115
|
}
|
|
24038
24116
|
}
|
|
24039
24117
|
if (choices.brief) {
|
|
24040
24118
|
ensureDeployaiDir(root);
|
|
24041
|
-
writeFileSync6(
|
|
24119
|
+
writeFileSync6(join8(root, BRIEF_FILE), `# The owner's details
|
|
24042
24120
|
|
|
24043
24121
|
${choices.brief}
|
|
24044
24122
|
`);
|
|
24045
24123
|
done.push(t("startBrief", { file: BRIEF_FILE }));
|
|
24046
24124
|
}
|
|
24125
|
+
if (runInit(root).created.includes("DEPLOYAI.md")) done.push(t("startRules"));
|
|
24047
24126
|
if (choices.projectId) {
|
|
24048
24127
|
const before = readProject(root);
|
|
24049
24128
|
writeProject(root, { ...before ?? {}, projectId: choices.projectId, name: choices.name ?? void 0, slug: choices.slug ?? void 0, createdAt: before?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -24069,7 +24148,7 @@ ${choices.brief}
|
|
|
24069
24148
|
}
|
|
24070
24149
|
|
|
24071
24150
|
// src/commands/addon.ts
|
|
24072
|
-
import { readFileSync as
|
|
24151
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
24073
24152
|
import { resolve as resolve3 } from "path";
|
|
24074
24153
|
function linkedProjectId2(root) {
|
|
24075
24154
|
const id = readProject(root)?.projectId;
|
|
@@ -24150,7 +24229,7 @@ async function addonDoneCommand(root, ctx, runId, opts) {
|
|
|
24150
24229
|
let report;
|
|
24151
24230
|
if (opts.report) {
|
|
24152
24231
|
try {
|
|
24153
|
-
report = JSON.parse(
|
|
24232
|
+
report = JSON.parse(readFileSync7(resolve3(root, opts.report), "utf8"));
|
|
24154
24233
|
} catch {
|
|
24155
24234
|
throw new CliError(`Cannot read the report file ${opts.report} as JSON.`, 1, "usage");
|
|
24156
24235
|
}
|
|
@@ -24246,7 +24325,7 @@ function buildProgram() {
|
|
|
24246
24325
|
const g = (cmd) => cmd.optsWithGlobals();
|
|
24247
24326
|
const root = (cmd) => resolve4(g(cmd).dir ?? process.cwd());
|
|
24248
24327
|
const ctx = (cmd) => apiContext(g(cmd).api);
|
|
24249
|
-
program.command("init").description("create DEPLOYAI.md and .deployai/ guard files").option("--force", "overwrite DEPLOYAI.md").action((opts, cmd) => initCommand(root(cmd), opts));
|
|
24328
|
+
program.command("init").description("create DEPLOYAI.md and .deployai/ guard files").option("--force", "overwrite DEPLOYAI.md").option("--no-agent-files", "do not add the DEPLOYAI.md line to AGENTS.md and CLAUDE.md").action((opts, cmd) => initCommand(root(cmd), opts));
|
|
24250
24329
|
program.command("inspect").description("show framework, package manager, language, database, storage").option("--json", "machine readable output").action((opts, cmd) => inspectCommand(root(cmd), opts));
|
|
24251
24330
|
program.command("check").description("can this project run on DeployAI: blockers and warnings, with the AI prompt").option("--json", "machine readable output").option("--no-clipboard", "do not copy the prompt to the clipboard").action(async (opts, cmd) => {
|
|
24252
24331
|
const a = await runCheck(root(cmd), ctx(cmd), opts);
|