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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +108 -29
  3. 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.6";
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 !== "DEPLOYAI.md" && !isEnvFile(f.rel.split("/").pop() ?? ""));
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
- Do not add:
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
- const analysis = analyzeProject(root);
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
- return { created, kept };
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
- out(" Run: npx deployai@latest check");
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 readFileSync5 } from "fs";
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: readFileSync5(f.abs),
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 existsSync6, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync5 } from "fs";
23746
- import { dirname, join as join6, relative, resolve, sep } from "path";
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 existsSync6(dir) ? readdirSync3(dir).filter((f) => !IGNORED.has(f)) : [];
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 = existsSync6(join6(base, "package.json"));
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 existsSync7, writeFileSync as writeFileSync6 } from "fs";
23996
- import { join as join7, relative as relative2, resolve as resolve2 } from "path";
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 (existsSync7(join7(root, "package.json"))) {
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(join7(root, BRIEF_FILE), `# The owner's details
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 readFileSync6 } from "fs";
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(readFileSync6(resolve3(root, opts.report), "utf8"));
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deployai",
3
- "version": "0.1.0-beta.6",
3
+ "version": "0.1.0-beta.8",
4
4
  "description": "Check a site built with an AI editor, see what has to change, and publish it to DeployAI. Hebrew first.",
5
5
  "keywords": [
6
6
  "deployai",