deployai 0.1.0-beta.5 → 0.1.0-beta.7

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 +137 -39
  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
@@ -12,6 +12,9 @@ import { Command } from "commander";
12
12
  // src/api.ts
13
13
  import { arch, platform } from "os";
14
14
 
15
+ // ../shared/src/plans.ts
16
+ var VAT_RATE = 0.18;
17
+
15
18
  // ../shared/src/blockers.ts
16
19
  var ISSUES = [
17
20
  // Blockers
@@ -20939,7 +20942,15 @@ var StatusResponse = external_exports.object({
20939
20942
  project: Project,
20940
20943
  queue: external_exports.object({ position: external_exports.number(), running: external_exports.boolean() }),
20941
20944
  /** The newest version, with the error and the end of the build log when it failed. */
20942
- latest: external_exports.object({ number: external_exports.number(), status: VersionStatus, error: external_exports.string().nullable(), logTail: external_exports.string().nullable(), migrationStatus: MigrationStatus.nullable().optional() }).nullable().optional()
20945
+ latest: external_exports.object({
20946
+ number: external_exports.number(),
20947
+ status: VersionStatus,
20948
+ error: external_exports.string().nullable(),
20949
+ logTail: external_exports.string().nullable(),
20950
+ migrationStatus: MigrationStatus.nullable().optional(),
20951
+ /** A ready version that is not live: its preview, for the owner to look at before promote (D-505). */
20952
+ preview: external_exports.string().nullable().optional()
20953
+ }).nullable().optional()
20943
20954
  });
20944
20955
  var ApiError = external_exports.object({
20945
20956
  error: external_exports.string(),
@@ -21127,17 +21138,17 @@ var ARCH_NODES = [
21127
21138
  { id: "board-watcher", kind: "actor", zone: "outside", label: "Board watcher", summary: "\u05E8\u05E5 \u05D0\u05E6\u05DC \u05D4\u05D1\u05E2\u05DC\u05D9\u05DD (pnpm board:watch): \u05DC\u05D5\u05E7\u05D7 \u05DB\u05E8\u05D8\u05D9\u05E1 \u05DE\u05DC\u05D5\u05D7 \u05D4\u05E2\u05D1\u05D5\u05D3\u05D4 (\u05E8\u05E7 \u05DB\u05E9\u05D4\u05DE\u05EA\u05D2 \u05E9\u05DC\u05D5 \u05D1\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA \u05E4\u05D5\u05E2\u05DC), \u05DE\u05E8\u05D9\u05E5 Claude Code \u05DC\u05E7\u05E8\u05D9\u05D0\u05D4 \u05D1\u05DC\u05D1\u05D3 \u05D5\u05DE\u05D7\u05D6\u05D9\u05E8 \u05EA\u05D5\u05DB\u05E0\u05D9\u05EA. \u05DB\u05E8\u05D8\u05D9\u05E1 \u05E2\u05DD \u05D1\u05E0\u05D9\u05D9\u05D4 \u05D0\u05D5\u05D8\u05D5\u05DE\u05D8\u05D9\u05EA \u05E9\u05D0\u05D5\u05E9\u05E8 \u05E0\u05D1\u05E0\u05D4 \u05D1\u05EA\u05D9\u05E7\u05D9\u05D9\u05EA \u05D4\u05E4\u05E8\u05D5\u05D9\u05E7\u05D8, \u05D0\u05D7\u05D3 \u05D1\u05DB\u05DC \u05E4\u05E2\u05DD. \u05D4\u05D5\u05D0 \u05D2\u05DD \u05DB\u05D5\u05EA\u05D1 \u05D2\u05E8\u05E1\u05D0\u05D5\u05EA \u05D7\u05D3\u05E9\u05D5\u05EA \u05DC\u05E1\u05E4\u05E8\u05D9\u05D9\u05EA \u05D4\u05E4\u05E8\u05D5\u05DE\u05E4\u05D8\u05D9\u05DD \u05DC\u05E4\u05D9 \u05D4\u05E2\u05E8\u05D5\u05EA \u05D4\u05D1\u05E2\u05DC\u05D9\u05DD, \u05DC\u05D1\u05D3\u05D9\u05E7\u05D4 \u05D5\u05E4\u05E8\u05E1\u05D5\u05DD.", summaryEn: "Runs on the owner computer (pnpm board:watch): claims a work board ticket (only while its settings switch is on), runs Claude Code read only and posts a plan back. An approved auto build ticket is built in the project folder, one at a time. It also writes new versions of prompt library prompts from the owner notes, for review and publishing.", code: ["scripts/board-watch.ts", "scripts/prompts-sync.ts"], env: ["BOARD_RUNNER_TOKEN", "BOARD_URL"], decisions: ["D-110", "D-127", "D-182", "D-250"] },
21128
21139
  { id: "visitor", kind: "actor", zone: "outside", label: "\u05DE\u05D1\u05E7\u05E8 \u05D1\u05D0\u05EA\u05E8", labelEn: "Site visitor", summary: "\u05DE\u05D1\u05E7\u05E8 \u05D1\u05D0\u05EA\u05E8 \u05E9\u05DC \u05DC\u05E7\u05D5\u05D7 \u05D1\u05DB\u05EA\u05D5\u05D1\u05EA <slug>.<\u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05D0\u05EA\u05E8\u05D9\u05DD> (\u05DB\u05DE\u05D5 deploy-net.com \u05D0\u05D5 freesite.click) \u05D0\u05D5 \u05D1\u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05DE\u05E9\u05DC\u05D5.", summaryEn: "A visitor on a customer site at <slug>.<a sites domain> (like deploy-net.com or freesite.click) or on their own domain." },
21129
21140
  // Platform
21130
- { id: "web", kind: "app", zone: "platform", label: "Web app (Next.js)", summary: "\u05D0\u05EA\u05E8 \u05D4\u05E9\u05D9\u05D5\u05D5\u05E7, \u05DC\u05D5\u05D7 \u05D4\u05D1\u05E7\u05E8\u05D4, \u05D4\u05D0\u05D3\u05DE\u05D9\u05DF \u05D5\u05D4\u05BEAPI \u05E9\u05DC \u05D4\u05BECLI. \u05DE\u05DB\u05E0\u05D9\u05E1 \u05E2\u05D1\u05D5\u05D3\u05D5\u05EA \u05DC\u05EA\u05D5\u05E8.", summaryEn: "The marketing site, the dashboard, the admin and the CLI API. Puts jobs in the queue.", code: ["apps/web/src/app", "apps/web/src/server"], env: ["DEPLOYAI_SPACE", "BETTER_AUTH_SECRET", "NEXT_PUBLIC_SUPPORT_WHATSAPP", "DEV_SUPERADMIN_PASSWORD"], portability: "Our app (site, dashboard, API, builds)", docs: ["docs/04-architecture.md"], decisions: ["D-020", "D-057", "D-104", "D-149", "D-238", "D-293"] },
21141
+ { id: "web", kind: "app", zone: "platform", label: "Web app (Next.js)", summary: "\u05D0\u05EA\u05E8 \u05D4\u05E9\u05D9\u05D5\u05D5\u05E7, \u05DC\u05D5\u05D7 \u05D4\u05D1\u05E7\u05E8\u05D4, \u05D4\u05D0\u05D3\u05DE\u05D9\u05DF \u05D5\u05D4\u05BEAPI \u05E9\u05DC \u05D4\u05BECLI. \u05DE\u05DB\u05E0\u05D9\u05E1 \u05E2\u05D1\u05D5\u05D3\u05D5\u05EA \u05DC\u05EA\u05D5\u05E8.", summaryEn: "The marketing site, the dashboard, the admin and the CLI API. Puts jobs in the queue.", code: ["apps/web/src/app", "apps/web/src/server"], env: ["DEPLOYAI_SPACE", "BETTER_AUTH_SECRET", "NEXT_PUBLIC_SUPPORT_WHATSAPP", "DEV_SUPERADMIN_PASSWORD", "OPENAI_APPS_CHALLENGE"], portability: "Our app (site, dashboard, API, builds)", docs: ["docs/04-architecture.md"], decisions: ["D-020", "D-057", "D-104", "D-149", "D-238", "D-293"] },
21131
21142
  { id: "queue", kind: "db", zone: "platform", label: "pg-boss queue", summary: "\u05DB\u05DC \u05DE\u05D4 \u05E9\u05D0\u05D9\u05D8\u05D9 \u05D0\u05D5 \u05E0\u05D5\u05D2\u05E2 \u05D1\u05BECloudflare \u05E8\u05E5 \u05DB\u05E2\u05D1\u05D5\u05D3\u05D4 \u05D1\u05EA\u05D5\u05E8.", summaryEn: "Everything slow or that touches Cloudflare runs as a job in the queue.", code: ["apps/web/src/server/queue.ts"], portability: "Job queue", decisions: ["D-058"] },
21132
21143
  { id: "worker", kind: "app", zone: "platform", label: "Job worker", summary: "\u05EA\u05D4\u05DC\u05D9\u05DA \u05E0\u05E4\u05E8\u05D3 \u05E9\u05DE\u05E8\u05D9\u05E5 \u05D0\u05EA \u05D4\u05E2\u05D1\u05D5\u05D3\u05D5\u05EA \u05DE\u05D4\u05EA\u05D5\u05E8: \u05D1\u05E0\u05D9\u05D9\u05D4, \u05D4\u05E2\u05DC\u05D0\u05D4, \u05E0\u05D9\u05EA\u05D5\u05D1, \u05D1\u05D9\u05E7\u05D5\u05E8\u05D9\u05DD, \u05E2\u05DC\u05D5\u05D9\u05D5\u05EA \u05D5\u05DE\u05D9\u05D9\u05DC\u05D9\u05DD \u05DC\u05DE\u05E9\u05E4\u05DA (pnpm worker, \u05D0\u05D5 pnpm worker:public \u05DE\u05D0\u05D7\u05D5\u05E8\u05D9 \u05D4\u05BEtunnel).", summaryEn: "A separate process that runs the queued jobs: build, upload, routing, visits, costs and lifecycle emails (pnpm worker, or pnpm worker:public behind the tunnel).", code: ["apps/web/src/server/worker.ts", "apps/web/src/server/jobs.ts", "apps/web/src/server/site-data.ts", "apps/web/src/server/lifecycle", "apps/web/src/server/host-report.ts"], env: ["BUILD_SLOTS", "LIFECYCLE_NOW", "A11Y_RENDER", "DOCKER_HOST", "HOST_REPORT_PATH"], decisions: ["D-058", "D-148", "D-180", "D-340"] },
21133
21144
  { id: "build", kind: "app", zone: "platform", label: "Build service (Docker)", summary: "\u05E7\u05D5\u05E0\u05D8\u05D9\u05D9\u05E0\u05E8 \u05D7\u05D3\u05E9 \u05DC\u05DB\u05DC \u05E9\u05DC\u05D1, \u05D1\u05DC\u05D9 \u05E1\u05D5\u05D3\u05D5\u05EA. \u05D1\u05D5\u05E0\u05D4 \u05D0\u05EA \u05D4\u05E7\u05D5\u05D3 \u05E9\u05DC \u05D4\u05DC\u05E7\u05D5\u05D7 \u05DC\u05E7\u05D5\u05D1\u05E5 Worker.", summaryEn: "A fresh container for every step, with no secrets. Builds the customer's code into a Worker file.", code: ["apps/web/src/server/build.ts"], env: ["BUILD_MODE"] },
21134
21145
  { id: "postgres", kind: "db", zone: "platform", label: "Postgres", summary: "\u05DE\u05E1\u05D3 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD \u05E9\u05DC\u05E0\u05D5: \u05DE\u05E9\u05EA\u05DE\u05E9\u05D9\u05DD, \u05D0\u05EA\u05E8\u05D9\u05DD, \u05D2\u05E8\u05E1\u05D0\u05D5\u05EA, \u05EA\u05E9\u05DC\u05D5\u05DE\u05D9\u05DD, \u05D1\u05D9\u05E7\u05D5\u05E8\u05D9\u05DD \u05D5\u05D9\u05D5\u05DE\u05DF. \u05D1\u05D9\u05D9\u05E6\u05D5\u05E8 \u05D2\u05D9\u05D1\u05D5\u05D9 pg_dump \u05DC\u05D9\u05DC\u05D9 \u05DC\u05D3\u05DC\u05D9 R2 \u05E0\u05E4\u05E8\u05D3 (14 \u05D9\u05D5\u05DE\u05D9\u05D9\u05DD, 4 \u05E9\u05D1\u05D5\u05E2\u05D9\u05D9\u05DD), \u05DE\u05D5\u05E6\u05E4\u05DF \u05D1\u05BEage, \u05D5\u05DE\u05D2\u05D1\u05D9\u05DD \u05D2\u05DD \u05D9\u05D3\u05E0\u05D9\u05EA \u05DE\u05D0\u05D3\u05DE\u05D9\u05DF, \u05E9\u05E8\u05EA, \u05D2\u05D9\u05D1\u05D5\u05D9\u05D9\u05DD.", summaryEn: "Our database: users, sites, versions, payments, visits and the audit log. In production a nightly pg_dump goes to its own R2 bucket (14 daily, 4 weekly), encrypted with age, plus manual copies from Admin, Server, Backups.", code: ["apps/web/src/server/db/schema.ts", "scripts/backup-db.sh", "apps/web/src/server/backups.ts"], env: ["DATABASE_URL", "BACKUP_S3_ACCESS_KEY_ID", "BACKUP_S3_SECRET_ACCESS_KEY", "BACKUP_AGE_RECIPIENT"], portability: "Our database", docs: ["docs/04-architecture.md", "docs/22-go-live.md", "docs/23-server.md"], decisions: ["D-336", "D-340"] },
21135
- { id: "files", kind: "storage", zone: "platform", label: "Version files", summary: "\u05D0\u05E8\u05DB\u05D9\u05D5\u05E0\u05D9 \u05DE\u05E7\u05D5\u05E8 \u05D5\u05EA\u05D5\u05E6\u05E8\u05D9 \u05D1\u05E0\u05D9\u05D9\u05D4 \u05E9\u05DC \u05DB\u05DC \u05D2\u05E8\u05E1\u05D4, \u05D3\u05E8\u05DA storage.ts \u05D1\u05DC\u05D1\u05D3. \u05D3\u05DC\u05D9 R2 \u05DC\u05DB\u05DC \u05E1\u05D1\u05D9\u05D1\u05D4, \u05D5\u05E0\u05D9\u05E7\u05D5\u05D9 \u05DC\u05D9\u05DC\u05D9 \u05E9\u05DC \u05E7\u05D1\u05E6\u05D9\u05DD \u05E9\u05D0\u05E3 \u05D2\u05E8\u05E1\u05D4 \u05DC\u05D0 \u05DE\u05E9\u05EA\u05DE\u05E9\u05EA \u05D1\u05D4\u05DD.", summaryEn: "Source archives and build output of every version, through storage.ts only. One R2 bucket per place, and a nightly sweep of files no version uses.", code: ["apps/web/src/server/storage.ts", "apps/web/src/server/storage-sweep.ts"], env: ["STORAGE_DIR", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY"], portability: "Version files (uploads and build output)", docs: ["docs/17-portability.md"], decisions: ["D-095", "D-096", "D-316"] },
21146
+ { id: "files", kind: "storage", zone: "platform", label: "Version files", summary: "\u05D0\u05E8\u05DB\u05D9\u05D5\u05E0\u05D9 \u05DE\u05E7\u05D5\u05E8 \u05D5\u05EA\u05D5\u05E6\u05E8\u05D9 \u05D1\u05E0\u05D9\u05D9\u05D4 \u05E9\u05DC \u05DB\u05DC \u05D2\u05E8\u05E1\u05D4, \u05D3\u05E8\u05DA storage.ts \u05D1\u05DC\u05D1\u05D3. \u05D3\u05DC\u05D9 R2 \u05DC\u05DB\u05DC \u05E1\u05D1\u05D9\u05D1\u05D4, \u05D5\u05E0\u05D9\u05E7\u05D5\u05D9 \u05DC\u05D9\u05DC\u05D9 \u05E9\u05DC \u05E7\u05D1\u05E6\u05D9\u05DD \u05E9\u05D0\u05E3 \u05D2\u05E8\u05E1\u05D4 \u05DC\u05D0 \u05DE\u05E9\u05EA\u05DE\u05E9\u05EA \u05D1\u05D4\u05DD. \u05D1\u05D9\u05D9\u05E6\u05D5\u05E8 \u05E9\u05D9\u05E7\u05D5\u05E3 \u05DC\u05D9\u05DC\u05D9 \u05DC\u05D3\u05DC\u05D9 \u05D4\u05D2\u05D9\u05D1\u05D5\u05D9\u05D9\u05DD, \u05EA\u05D7\u05EA files/ (D-473).", summaryEn: "Source archives and build output of every version, through storage.ts only. One R2 bucket per place, and a nightly sweep of files no version uses. In prod a nightly mirror into the backups bucket, under files/ (D-473).", code: ["apps/web/src/server/storage.ts", "apps/web/src/server/storage-sweep.ts", "scripts/mirror-files.sh"], env: ["STORAGE_DIR", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY"], portability: "Version files (uploads and build output)", docs: ["docs/17-portability.md"], decisions: ["D-095", "D-096", "D-316", "D-473"] },
21136
21147
  // Services
21137
21148
  { id: "email-sending", kind: "external", zone: "services", label: "CF Email Sending", summary: "\u05E9\u05DC\u05D9\u05D7\u05EA \u05DE\u05D9\u05D9\u05DC\u05D9\u05DD \u05D3\u05E8\u05DA Cloudflare Email Sending. \u05D1\u05DC\u05D9 \u05D8\u05D5\u05E7\u05DF \u05D4\u05DE\u05D9\u05D9\u05DC \u05DE\u05D5\u05D3\u05E4\u05E1 \u05D1\u05DC\u05D5\u05D2.", summaryEn: "Sends email through Cloudflare Email Sending. Without a token, the email is printed to the log.", code: ["apps/web/src/server/email.ts"], portability: "Emails" },
21138
21149
  { id: "oauth", kind: "external", zone: "services", label: "Google / GitHub OAuth", summary: "\u05D4\u05EA\u05D7\u05D1\u05E8\u05D5\u05EA \u05E2\u05DD Google \u05D0\u05D5 GitHub \u05D3\u05E8\u05DA Better Auth.", summaryEn: "Log in with Google or GitHub through Better Auth.", code: ["apps/web/src/server/auth.ts"], env: ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET"], decisions: ["D-020"] },
21139
21150
  { id: "payments", kind: "external", zone: "services", label: "Payment provider (Cardcom)", summary: "\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC, \u05D5\u05E0\u05D1\u05D7\u05E8 \u05D1\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA \u05D4\u05D0\u05D3\u05DE\u05D9\u05DF (\u05D0\u05D5 \u05DE\u05D3\u05D5\u05DE\u05D4 \u05DC\u05D1\u05D3\u05D9\u05E7\u05D5\u05EA). \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1 \u05DE\u05D5\u05E7\u05DC\u05D3 \u05D1\u05D3\u05E3 \u05D4\u05DE\u05D0\u05D5\u05D1\u05D8\u05D7 \u05E9\u05DC \u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05D5\u05E0\u05E9\u05DE\u05E8 \u05DB\u05D8\u05D5\u05E7\u05DF \u05DE\u05D5\u05E6\u05E4\u05DF, \u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05E2\u05DD \u05DE\u05E4\u05EA\u05D7 \u05D0\u05D9\u05D3\u05DE\u05E4\u05D5\u05D8\u05E0\u05D8\u05D9\u05D5\u05EA, \u05D5\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DE\u05E4\u05D9\u05E7\u05D4 \u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05DE\u05E1 \u05DC\u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05D5\u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05D6\u05D9\u05DB\u05D5\u05D9 \u05DC\u05DB\u05DC \u05D4\u05D7\u05D6\u05E8.", summaryEn: "Cardcom by default, chosen in admin settings (or simulated for tests). The card is typed on the secure Cardcom page and saved as a sealed token, every charge carries an idempotency key, and Cardcom issues a tax invoice per charge and a credit invoice per refund.", code: ["apps/web/src/server/billing/provider.ts", "apps/web/src/server/billing/cardcom.ts", "apps/web/src/server/billing/card-pages.ts", "apps/web/src/app/api/billing/card"], env: ["BILLING_PROVIDER", "BILLING_MOCK_FAIL", "CARDCOM_TERMINAL", "CARDCOM_API_NAME", "CARDCOM_API_PASSWORD", "CARDCOM_INVOICES", "CARDCOM_CSS_URL", "CARDCOM_TOKEN_KEY", "CARDCOM_DEPARTMENT_ID"], portability: "Payments", decisions: ["D-175", "D-292"] },
21140
- { id: "registrar", kind: "external", zone: "services", label: "Domain registrars (Cloudflare, LiveDNS)", summary: "\u05E7\u05E0\u05D9\u05D9\u05EA \u05D3\u05D5\u05DE\u05D9\u05D9\u05E0\u05D9\u05DD \u05DC\u05D0\u05EA\u05E8: \u05DB\u05DC \u05E9\u05DD \u05D4\u05D5\u05DC\u05DA \u05DC\u05E8\u05E9\u05DD \u05D4\u05D6\u05D5\u05DC \u05D1\u05D9\u05D5\u05EA\u05E8 \u05E9\u05E4\u05D5\u05E2\u05DC (Cloudflare \u05D1\u05D3\u05D5\u05DC\u05E8\u05D9\u05DD, LiveDNS \u05DC\u05D9\u05E9\u05E8\u05D0\u05DC\u05D9\u05D9\u05DD \u05DE\u05E7\u05E8\u05D3\u05D9\u05D8 \u05D1\u05E9\u05E7\u05DC\u05D9\u05DD, \u05D0\u05D5 \u05D9\u05D3\u05E0\u05D9 \u05DE\u05EA\u05D5\u05E8 \u05D4\u05E6\u05D5\u05D5\u05EA), \u05E8\u05D9\u05E9\u05D5\u05DD \u05D0\u05D7\u05D3 \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D9\u05D5\u05DE\u05DF \u05E7\u05E8\u05D9\u05D0\u05D5\u05EA \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D5\u05D7\u05D9\u05D3\u05D5\u05E9 \u05E9\u05E0\u05EA\u05D9 \u05D0\u05E6\u05DC \u05D0\u05D5\u05EA\u05D5 \u05E8\u05E9\u05DD. \u05DC\u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05E9\u05E0\u05E7\u05E0\u05D4: \u05D3\u05D5\u05D0\u05E8 \u05D3\u05E8\u05DA Cloudflare Email Routing.", summaryEn: "Buying domains for a site: each name goes to the cheapest registrar that is on (Cloudflare in dollars, LiveDNS for Israeli names from shekel credit, or by hand from the team queue), one registration per order, a call log per order, yearly renewal at the same registrar. For a bought domain: email through Cloudflare Email Routing.", code: ["apps/web/src/server/registrar.ts", "apps/web/src/server/registrar-livedns.ts", "apps/web/src/server/registrar-log.ts", "apps/web/src/server/domain-sales.ts", "apps/web/src/server/domain-email.ts", "apps/web/src/server/billing/services.ts"], env: ["CF_REGISTRAR_TOKEN", "LIVEDNS_USER", "LIVEDNS_PASSWORD"], decisions: ["D-299", "D-300", "D-301", "D-458"] },
21151
+ { id: "registrar", kind: "external", zone: "services", label: "Domain registrars (Cloudflare, LiveDNS)", summary: "\u05E7\u05E0\u05D9\u05D9\u05EA \u05D3\u05D5\u05DE\u05D9\u05D9\u05E0\u05D9\u05DD \u05DC\u05D0\u05EA\u05E8: \u05DB\u05DC \u05E9\u05DD \u05D4\u05D5\u05DC\u05DA \u05DC\u05E8\u05E9\u05DD \u05D4\u05D6\u05D5\u05DC \u05D1\u05D9\u05D5\u05EA\u05E8 \u05E9\u05E4\u05D5\u05E2\u05DC, \u05DB\u05DC \u05E8\u05E9\u05DD \u05D1\u05E2\u05DC\u05D5\u05EA \u05D5\u05D1\u05E2\u05DE\u05DC\u05D4 \u05DE\u05E9\u05DC\u05D5 (Cloudflare \u05D1\u05D3\u05D5\u05DC\u05E8\u05D9\u05DD \u05DC\u05DB\u05DC \u05E9\u05DD, LiveDNS \u05DE\u05E0\u05E7\u05D5\u05D3\u05D5\u05EA \u05E7\u05E8\u05D3\u05D9\u05D8 \u05DC\u05E4\u05D9 \u05D4\u05DE\u05D7\u05D9\u05E8\u05D5\u05DF \u05E9\u05E0\u05E7\u05E8\u05D0 \u05DB\u05DC \u05D9\u05D5\u05DD, \u05D0\u05D5 \u05D9\u05D3\u05E0\u05D9 \u05DE\u05EA\u05D5\u05E8 \u05D4\u05E6\u05D5\u05D5\u05EA), \u05DE\u05D7\u05D9\u05E8 \u05DB\u05DC \u05E1\u05D9\u05D5\u05DE\u05EA \u05E0\u05D1\u05D3\u05E7 \u05DB\u05DC \u05D9\u05D5\u05DD (\u05D5\u05D0\u05E4\u05E9\u05E8 \u05DC\u05DB\u05D1\u05D5\u05EA \u05E1\u05D9\u05D5\u05DE\u05D5\u05EA), \u05E8\u05D9\u05E9\u05D5\u05DD \u05D0\u05D7\u05D3 \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D9\u05D5\u05DE\u05DF \u05E7\u05E8\u05D9\u05D0\u05D5\u05EA \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D5\u05D7\u05D9\u05D3\u05D5\u05E9 \u05E9\u05E0\u05EA\u05D9 \u05D0\u05E6\u05DC \u05D0\u05D5\u05EA\u05D5 \u05E8\u05E9\u05DD. \u05DC\u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05E9\u05E0\u05E7\u05E0\u05D4: \u05D3\u05D5\u05D0\u05E8 \u05D3\u05E8\u05DA Cloudflare Email Routing.", summaryEn: "Buying domains for a site: each name goes to the cheapest registrar that is on, each with its own cost and fee (Cloudflare in dollars per name, LiveDNS from credit points priced by its list, read daily, or by hand from the team queue), the price of every extension checked daily (some can be turned off), one registration per order, a call log per order, yearly renewal at the same registrar. For a bought domain: email through Cloudflare Email Routing.", code: ["apps/web/src/server/registrar.ts", "apps/web/src/server/registrar-livedns.ts", "apps/web/src/server/registrar-log.ts", "apps/web/src/server/domain-sales.ts", "apps/web/src/server/domain-extensions.ts", "apps/web/src/server/domain-email.ts", "apps/web/src/server/billing/services.ts"], env: ["CF_REGISTRAR_TOKEN", "LIVEDNS_USER", "LIVEDNS_PASSWORD"], decisions: ["D-299", "D-300", "D-301", "D-458", "D-486", "D-489", "D-491"] },
21141
21152
  { id: "mcp", kind: "external", zone: "services", label: "MCP for AI tools (/api/mcp)", summary: "ChatGPT \u05D5\u05BEClaude \u05DE\u05EA\u05D7\u05D1\u05E8\u05D9\u05DD \u05D1\u05DC\u05D9 \u05D8\u05E8\u05DE\u05D9\u05E0\u05DC: OAuth \u05E2\u05DD \u05D0\u05D9\u05E9\u05D5\u05E8 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF, \u05D5\u05D0\u05D6 \u05DB\u05DC\u05D9\u05DD \u05DC\u05E8\u05E9\u05D9\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8\u05D9\u05DD, \u05D1\u05D3\u05D9\u05E7\u05D4, \u05D4\u05E2\u05DC\u05D0\u05EA \u05D2\u05E8\u05E1\u05D4 \u05DC\u05EA\u05E6\u05D5\u05D2\u05D4 \u05DE\u05E7\u05D3\u05D9\u05DE\u05D4, \u05D4\u05E8\u05E6\u05EA \u05EA\u05D5\u05E1\u05E4\u05D9\u05DD \u05E9\u05D4\u05D0\u05EA\u05E8 \u05E7\u05E0\u05D4 (\u05D4\u05E7\u05E0\u05D9\u05D9\u05D4 \u05E8\u05E7 \u05D1\u05D0\u05EA\u05E8), \u05D5\u05D4\u05E2\u05DC\u05D0\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05E8\u05E7 \u05E2\u05DD \u05D4\u05E8\u05E9\u05D0\u05D4 \u05D5\u05D0\u05D9\u05E9\u05D5\u05E8.", summaryEn: "ChatGPT and Claude connect without a terminal: OAuth with a browser consent, then tools to list sites, check, upload a version to a preview, run add-ons the site owns (buying stays on the site), and go live only with the permission and a yes.", code: ["apps/web/src/app/api/mcp/route.ts", "apps/web/src/server/mcp-tools.ts", "apps/web/src/server/auth.ts"], decisions: ["D-302"] },
21142
21153
  { id: "npm", kind: "external", zone: "services", label: "npm registry", summary: "\u05DE\u05E4\u05D9\u05E5 \u05D0\u05EA \u05D4\u05BECLI, \u05D5\u05DE\u05DE\u05E0\u05D5 \u05D4\u05D1\u05E0\u05D9\u05D9\u05D4 \u05DE\u05EA\u05E7\u05D9\u05E0\u05D4 \u05EA\u05DC\u05D5\u05D9\u05D5\u05EA.", summaryEn: "Distributes the CLI, and the build installs dependencies from it." },
21143
21154
  { id: "pagespeed", kind: "external", zone: "services", label: "Google PageSpeed Insights", summary: "\u05D1\u05D3\u05D9\u05E7\u05D5\u05EA \u05D4\u05DE\u05D4\u05D9\u05E8\u05D5\u05EA, \u05D4\u05E0\u05D2\u05D9\u05E9\u05D5\u05EA \u05D5\u05D4\u05BESEO \u05D4\u05D7\u05D9\u05E0\u05DE\u05D9\u05D5\u05EA: Lighthouse \u05D1\u05DE\u05E2\u05D1\u05D3\u05D4 \u05E9\u05DC \u05D2\u05D5\u05D2\u05DC (\u05DB\u05D5\u05DC\u05DC \u05E1\u05D5\u05DB\u05E0\u05D9 AI) \u05D5\u05E0\u05EA\u05D5\u05E0\u05D9 \u05DE\u05D1\u05E7\u05E8\u05D9\u05DD \u05D0\u05DE\u05D9\u05EA\u05D9\u05D9\u05DD.", summaryEn: "The free speed, accessibility and SEO tests: Lighthouse run at Google (AI agents included) plus real visitor data.", env: ["PAGESPEED_API_KEY"], decisions: ["D-199", "D-222"] },
@@ -21354,7 +21365,7 @@ var CLI_MAP_NODES = [
21354
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."),
21355
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."),
21356
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."),
21357
- 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."),
21358
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."),
21359
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."),
21360
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."),
@@ -21489,6 +21500,13 @@ function neverUploadedFile(rel) {
21489
21500
 
21490
21501
  // ../shared/src/domain-sales.ts
21491
21502
  var IL_TLDS = ["co.il", "org.il", "net.il"];
21503
+ var DEFAULT_LIVEDNS_POINTS = { 5: 9100, 10: 8900, 20: 8700, 50: 8500, 100: 8200 };
21504
+ var pointCost = (points, pack) => Math.round(points[pack] / (1 + VAT_RATE));
21505
+ var DEFAULT_DOMAIN_REGISTRARS = {
21506
+ cloudflare: { enabled: true, feeRate: 0.03, maxUsdCentsPerDay: 1e4 },
21507
+ livedns: { enabled: true, feeRate: 0.01, pack: 5, costAgorot: pointCost(DEFAULT_LIVEDNS_POINTS, 5) },
21508
+ manual: { enabled: true, feeRate: 0.01, costAgorot: 7500 }
21509
+ };
21492
21510
  var LIVEDNS_TLDS = [...IL_TLDS, "com", "net", "org"];
21493
21511
 
21494
21512
  // ../shared/src/env-scopes.ts
@@ -21498,6 +21516,7 @@ var ENV_KEYS = {
21498
21516
  BETTER_AUTH_SECRET: { scope: "own", section: "app", required: ["server"], sample: { local: "change-me-to-a-long-random-string", server: "" }, about: "Signs login sessions and our own links; changing it logs everyone out. 32 characters or more in production: openssl rand -base64 48" },
21499
21517
  DEV_SUPERADMIN_PASSWORD: { scope: "local", section: "app", about: "The superadmin password after every local wipe. Without it the one in apps/web/local-logins.md is kept (D-100)." },
21500
21518
  NEXT_PUBLIC_SUPPORT_WHATSAPP: { scope: "same", section: "app", about: "The WhatsApp number people reach us on, digits with the country code (972...). Empty shows only the email (D-237)." },
21519
+ OPENAI_APPS_CHALLENGE: { scope: "server", section: "app", about: "The domain check token from the OpenAI platform portal (Plugins, domain verification), served as plain text at /.well-known/openai-apps-challenge (D-474). Unset: that page is a 404." },
21501
21520
  TUNNEL_ORIGIN_CERT: { scope: "local", section: "app", about: "The cloudflared login certificate pnpm dev:public checks. Default ~/.cloudflared/cert.pem." },
21502
21521
  CF_API_TOKEN: { scope: "own", section: "cloudflare", required: ["server"], about: "Cloudflare token (pnpm cf:token-link): sites, KV, D1, R2, routes, custom hostnames and our emails. Each machine its own. Without it everything Cloudflare is a dry run." },
21503
21522
  CF_REGISTRAR_TOKEN: { scope: "server", section: "cloudflare", about: "Buys real domains (D-300): a Cloudflare token with Registrar edit only. Server only." },
@@ -21624,6 +21643,26 @@ var SPACES = {
21624
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" })
21625
21644
  };
21626
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
+
21627
21666
  // src/config.ts
21628
21667
  import { randomUUID } from "crypto";
21629
21668
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -21771,6 +21810,7 @@ var M = {
21771
21810
  startInstalled: "Installed its packages (npm install).",
21772
21811
  startBrief: "Wrote the owner's details to {file} (kept out of git and never uploaded).",
21773
21812
  startLinked: 'Linked this folder to the site "{name}".',
21813
+ startRules: "Wrote the rules for your agent to DEPLOYAI.md (never uploaded).",
21774
21814
  startRelinked: 'Linked this folder to the site "{name}" instead of the site it was linked to.',
21775
21815
  statusLine: "Status: {s}",
21776
21816
  ready: "ready",
@@ -21784,6 +21824,7 @@ var M = {
21784
21824
  pasteFix: " Paste the prompt below into your AI editor, then run: npx deployai@latest check",
21785
21825
  copied: " (copied to clipboard)",
21786
21826
  runDeploy: ' Run: npx deployai@latest deploy -m "<message>"',
21827
+ initHint: " So your agent follows the DeployAI rules, run: npx deployai@latest init",
21787
21828
  deployTitle: "DeployAI deploy",
21788
21829
  guestTitle: "DeployAI deploy (no account)",
21789
21830
  uploading: "Uploading...",
@@ -21826,20 +21867,22 @@ var M = {
21826
21867
  liveVersion: "Live version",
21827
21868
  newestVersion: "Newest version",
21828
21869
  promoteReady: " After the owner approves the preview: npx deployai@latest promote v{n} (to put it live)",
21870
+ askOwner: ' Version {n} is ready and not live. Ask the owner: "Version {n} is ready. Do you want to put it live?"',
21871
+ showPreview: " Send them the preview first: {url}",
21829
21872
  notPublished: "not published yet",
21830
21873
  none: "none",
21831
21874
  buildingNow: "building now",
21832
21875
  idle: "idle",
21833
21876
  envListTitle: "Variables",
21834
- envNone: "This site has no variables yet. Add one: npx deployai@latest env set <key> <value>",
21877
+ envNone: "This site has no variables yet. Add one: npx deployai@latest env set <KEY> <value>",
21835
21878
  envSecret: "secret",
21836
21879
  envPlain: "plain",
21837
- envNeedValue: 'Give the value after the key, or pipe it in: echo "<value>" | npx deployai@latest env set <key>',
21880
+ envNeedValue: 'Give the value after the key, or pipe it in: echo "<value>" | npx deployai@latest env set <KEY>',
21838
21881
  envSavedSecret: "Saved {key} as a secret on the live site. Its value is not stored and is never shown again.",
21839
21882
  envSavedPlain: "Saved {key}. The live site gets it in about a minute.",
21840
21883
  envRemoved: "Removed {key}. The live site loses it in about a minute.",
21841
21884
  guestNoEnv: "A temporary site has no environment variables. Keep it in an account first: npx deployai@latest claim",
21842
- envInvalidKey: "A variable name is English letters, digits and _, does not start with a digit, up to 64 characters.",
21885
+ envInvalidKey: "A variable name is capital English letters, digits and _, starts with a letter, up to 64 characters, like STRIPE_KEY.",
21843
21886
  envTooLong: "The value is over 5 KB, too long for a variable.",
21844
21887
  envSendFailed: "The secret did not reach the site. Try again in a minute.",
21845
21888
  envNoKey: "This site has no variable with that name. See them: npx deployai@latest env list",
@@ -21938,6 +21981,7 @@ var M = {
21938
21981
  startInstalled: "\u05D4\u05D7\u05D1\u05D9\u05DC\u05D5\u05EA \u05E9\u05DC\u05D4 \u05D4\u05D5\u05EA\u05E7\u05E0\u05D5 (npm install).",
21939
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).",
21940
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).",
21941
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.',
21942
21986
  statusLine: "\u05DE\u05E6\u05D1: {s}",
21943
21987
  ready: "\u05DE\u05D5\u05DB\u05DF \u05DC\u05E2\u05DC\u05D5\u05EA",
@@ -21951,6 +21995,7 @@ var M = {
21951
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",
21952
21996
  copied: " (\u05D4\u05D5\u05E2\u05EA\u05E7)",
21953
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",
21954
21999
  deployTitle: "DeployAI deploy",
21955
22000
  guestTitle: "DeployAI deploy (\u05D1\u05DC\u05D9 \u05D7\u05E9\u05D1\u05D5\u05DF)",
21956
22001
  uploading: "\u05DE\u05E2\u05DC\u05D9\u05DD...",
@@ -21993,20 +22038,22 @@ var M = {
21993
22038
  liveVersion: "\u05D2\u05E8\u05E1\u05D4 \u05D7\u05D9\u05D4",
21994
22039
  newestVersion: "\u05D2\u05E8\u05E1\u05D4 \u05D0\u05D7\u05E8\u05D5\u05E0\u05D4",
21995
22040
  promoteReady: " \u05D0\u05D7\u05E8\u05D9 \u05E9\u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8 \u05D0\u05D9\u05E9\u05E8 \u05D0\u05EA \u05D4\u05EA\u05E6\u05D5\u05D2\u05D4 \u05D4\u05DE\u05E7\u05D3\u05D9\u05DE\u05D4: npx deployai@latest promote v{n} (\u05DB\u05D3\u05D9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05D0\u05D5\u05EA\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8)",
22041
+ askOwner: ' \u05D2\u05E8\u05E1\u05D4 {n} \u05DE\u05D5\u05DB\u05E0\u05D4 \u05D5\u05E2\u05D5\u05D3 \u05DC\u05D0 \u05D1\u05D0\u05D5\u05D5\u05D9\u05E8. \u05E9\u05D0\u05DC\u05D5 \u05D0\u05EA \u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8: "\u05D2\u05E8\u05E1\u05D4 {n} \u05DE\u05D5\u05DB\u05E0\u05D4. \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05D0\u05D5\u05EA\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8?"',
22042
+ showPreview: " \u05E9\u05DC\u05D7\u05D5 \u05E7\u05D5\u05D3\u05DD \u05D0\u05EA \u05D4\u05EA\u05E6\u05D5\u05D2\u05D4 \u05D4\u05DE\u05E7\u05D3\u05D9\u05DE\u05D4: {url}",
21996
22043
  notPublished: "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DC\u05D0 \u05D1\u05D0\u05D5\u05D5\u05D9\u05E8",
21997
22044
  none: "\u05D0\u05D9\u05DF",
21998
22045
  buildingNow: "\u05D1\u05D5\u05E0\u05D9\u05DD \u05E2\u05DB\u05E9\u05D9\u05D5",
21999
22046
  idle: "\u05E4\u05E0\u05D5\u05D9",
22000
22047
  envListTitle: "\u05DE\u05E9\u05EA\u05E0\u05D9\u05DD",
22001
- envNone: "\u05DC\u05D0\u05EA\u05E8 \u05D4\u05D6\u05D4 \u05E2\u05D5\u05D3 \u05D0\u05D9\u05DF \u05DE\u05E9\u05EA\u05E0\u05D9\u05DD. \u05D4\u05D5\u05E1\u05D9\u05E4\u05D5 \u05D0\u05D7\u05D3: npx deployai@latest env set <key> <value>",
22048
+ envNone: "\u05DC\u05D0\u05EA\u05E8 \u05D4\u05D6\u05D4 \u05E2\u05D5\u05D3 \u05D0\u05D9\u05DF \u05DE\u05E9\u05EA\u05E0\u05D9\u05DD. \u05D4\u05D5\u05E1\u05D9\u05E4\u05D5 \u05D0\u05D7\u05D3: npx deployai@latest env set <KEY> <value>",
22002
22049
  envSecret: "\u05E1\u05D5\u05D3",
22003
22050
  envPlain: "\u05D2\u05DC\u05D5\u05D9",
22004
- envNeedValue: '\u05DB\u05EA\u05D1\u05D5 \u05D0\u05EA \u05D4\u05E2\u05E8\u05DA \u05D0\u05D7\u05E8\u05D9 \u05D4\u05E9\u05DD, \u05D0\u05D5 \u05D4\u05E2\u05D1\u05D9\u05E8\u05D5 \u05D0\u05D5\u05EA\u05D5 \u05D1\u05E6\u05D9\u05E0\u05D5\u05E8: echo "<value>" | npx deployai@latest env set <key>',
22051
+ envNeedValue: '\u05DB\u05EA\u05D1\u05D5 \u05D0\u05EA \u05D4\u05E2\u05E8\u05DA \u05D0\u05D7\u05E8\u05D9 \u05D4\u05E9\u05DD, \u05D0\u05D5 \u05D4\u05E2\u05D1\u05D9\u05E8\u05D5 \u05D0\u05D5\u05EA\u05D5 \u05D1\u05E6\u05D9\u05E0\u05D5\u05E8: echo "<value>" | npx deployai@latest env set <KEY>',
22005
22052
  envSavedSecret: "\u05E9\u05DE\u05E8\u05E0\u05D5 \u05D0\u05EA {key} \u05DB\u05E1\u05D5\u05D3 \u05D1\u05D0\u05EA\u05E8 \u05D4\u05D7\u05D9. \u05D4\u05E2\u05E8\u05DA \u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8 \u05D0\u05E6\u05DC\u05E0\u05D5 \u05D5\u05DC\u05D0 \u05D9\u05D5\u05E6\u05D2 \u05E9\u05D5\u05D1.",
22006
22053
  envSavedPlain: "\u05E9\u05DE\u05E8\u05E0\u05D5 \u05D0\u05EA {key}. \u05D4\u05D0\u05EA\u05E8 \u05D4\u05D7\u05D9 \u05D9\u05E7\u05D1\u05DC \u05D0\u05D5\u05EA\u05D5 \u05EA\u05D5\u05DA \u05DB\u05D3\u05E7\u05D4.",
22007
22054
  envRemoved: "\u05D4\u05E1\u05E8\u05E0\u05D5 \u05D0\u05EA {key}. \u05D4\u05D5\u05D0 \u05D9\u05D9\u05E2\u05DC\u05DD \u05DE\u05D4\u05D0\u05EA\u05E8 \u05D4\u05D7\u05D9 \u05EA\u05D5\u05DA \u05DB\u05D3\u05E7\u05D4.",
22008
22055
  guestNoEnv: "\u05DC\u05D0\u05EA\u05E8 \u05D6\u05DE\u05E0\u05D9 \u05D0\u05D9\u05DF \u05DE\u05E9\u05EA\u05E0\u05D9 \u05E1\u05D1\u05D9\u05D1\u05D4. \u05E9\u05DE\u05E8\u05D5 \u05D0\u05D5\u05EA\u05D5 \u05DC\u05D7\u05E9\u05D1\u05D5\u05DF \u05E7\u05D5\u05D3\u05DD: npx deployai@latest claim",
22009
- envInvalidKey: "\u05E9\u05DD \u05DE\u05E9\u05EA\u05E0\u05D4: \u05D0\u05D5\u05EA\u05D9\u05D5\u05EA \u05D1\u05D0\u05E0\u05D2\u05DC\u05D9\u05EA, \u05E1\u05E4\u05E8\u05D5\u05EA \u05D5-_, \u05DC\u05D0 \u05DE\u05EA\u05D7\u05D9\u05DC \u05D1\u05E1\u05E4\u05E8\u05D4, \u05E2\u05D3 64 \u05EA\u05D5\u05D5\u05D9\u05DD.",
22056
+ envInvalidKey: "\u05E9\u05DD \u05DE\u05E9\u05EA\u05E0\u05D4: \u05D0\u05D5\u05EA\u05D9\u05D5\u05EA \u05D2\u05D3\u05D5\u05DC\u05D5\u05EA \u05D1\u05D0\u05E0\u05D2\u05DC\u05D9\u05EA, \u05E1\u05E4\u05E8\u05D5\u05EA \u05D5-_, \u05DE\u05EA\u05D7\u05D9\u05DC \u05D1\u05D0\u05D5\u05EA, \u05E2\u05D3 64 \u05EA\u05D5\u05D5\u05D9\u05DD, \u05DB\u05DE\u05D5 STRIPE_KEY.",
22010
22057
  envTooLong: "\u05D4\u05E2\u05E8\u05DA \u05D2\u05D3\u05D5\u05DC \u05DE\u05BE5KB, \u05D0\u05E8\u05D5\u05DA \u05DE\u05D3\u05D9 \u05DC\u05DE\u05E9\u05EA\u05E0\u05D4.",
22011
22058
  envSendFailed: "\u05D4\u05E1\u05D5\u05D3 \u05DC\u05D0 \u05D4\u05D2\u05D9\u05E2 \u05DC\u05D0\u05EA\u05E8. \u05E0\u05E1\u05D5 \u05E9\u05D5\u05D1 \u05D1\u05E2\u05D5\u05D3 \u05D3\u05E7\u05D4.",
22012
22059
  envNoKey: "\u05DC\u05D0\u05EA\u05E8 \u05D0\u05D9\u05DF \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05E9\u05DD \u05D4\u05D6\u05D4. \u05DC\u05E8\u05E9\u05D9\u05DE\u05D4: npx deployai@latest env list",
@@ -22109,7 +22156,7 @@ function messages(root) {
22109
22156
  }
22110
22157
 
22111
22158
  // src/version.ts
22112
- var CLI_VERSION = "0.1.0-beta.5";
22159
+ var CLI_VERSION = "0.1.0-beta.7";
22113
22160
 
22114
22161
  // src/api.ts
22115
22162
  function apiContext(apiFlag) {
@@ -22338,7 +22385,7 @@ async function sendTelemetryEvent(ctx, event) {
22338
22385
  }
22339
22386
 
22340
22387
  // src/commands/init.ts
22341
- import { existsSync as existsSync5, writeFileSync as writeFileSync3 } from "fs";
22388
+ import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
22342
22389
  import { join as join5 } from "path";
22343
22390
 
22344
22391
  // src/analyze.ts
@@ -22506,6 +22553,7 @@ function planUpload(root) {
22506
22553
  }
22507
22554
 
22508
22555
  // src/analyze.ts
22556
+ var INIT_FILES = /* @__PURE__ */ new Set(["DEPLOYAI.md", "AGENTS.md", "CLAUDE.md"]);
22509
22557
  var CODE_EXT = /\.(js|jsx|ts|tsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
22510
22558
  var SECRET_SCAN_EXT = /\.(js|jsx|ts|tsx|mjs|cjs|mts|cts|vue|svelte|astro|json|ya?ml|toml|html|prisma)$/;
22511
22559
  var LOCKFILES = /* @__PURE__ */ new Set(["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"]);
@@ -22863,7 +22911,7 @@ function analyzeProject(root) {
22863
22911
  }
22864
22912
  const otherStack = detectOtherStack(files.map((f) => f.rel));
22865
22913
  if (otherStack) add({ code: "other_stack", severity: "blocker", detail: ` ${otherStack.name}` });
22866
- 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() ?? ""));
22867
22915
  if (empty) add({ code: "no_files", severity: "blocker" });
22868
22916
  if (framework.id === "unknown" && !otherStack && !empty) {
22869
22917
  add({ code: "unknown_framework", severity: "warning", detail: framework.flavor ? ` (looks like ${framework.flavor})` : "" });
@@ -22961,13 +23009,28 @@ This project is published with DeployAI.
22961
23009
 
22962
23010
  Always explain to the user in simple words, in the language they write to you in. The user may not read English.
22963
23011
 
22964
- Do not add:
23012
+ 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.
23013
+
23014
+ ## Build with
23015
+
23016
+ ${BUILD_WITH.map((l) => `- ${l}`).join("\n")}
23017
+
23018
+ To start from working code, see the samples: npx deployai@latest samples
23019
+
23020
+ ## Do not add
23021
+
22965
23022
  - local file system writes
22966
23023
  - database drivers DeployAI does not support (see: npx deployai@latest inspect)
22967
23024
  - long-running processes or background servers
22968
23025
  - native binary modules
22969
23026
  - DeployAI or any cloud credentials in source code
22970
23027
 
23028
+ ## Keep existing data
23029
+
23030
+ ${KEEP_DATA_RULES.join("\n")}
23031
+
23032
+ ## Check
23033
+
22971
23034
  Before adding a dependency or a new server feature, run: npx deployai@latest check
22972
23035
  Ask the developer before removing any existing functionality.
22973
23036
 
@@ -22975,9 +23038,11 @@ Files:
22975
23038
  - .deployai/project.json: project id and settings (safe to commit)
22976
23039
  - .deployai/last-check.json: latest check result (not committed)
22977
23040
  `;
23041
+ var AGENT_FILES = ["AGENTS.md", "CLAUDE.md"];
22978
23042
  function runInit(root, opts = {}) {
22979
23043
  const created = [];
22980
23044
  const kept = [];
23045
+ const updated = [];
22981
23046
  const md = join5(root, "DEPLOYAI.md");
22982
23047
  if (existsSync5(md) && !opts.force) {
22983
23048
  kept.push("DEPLOYAI.md");
@@ -22985,20 +23050,35 @@ function runInit(root, opts = {}) {
22985
23050
  writeFileSync3(md, DEPLOYAI_MD);
22986
23051
  created.push("DEPLOYAI.md");
22987
23052
  }
23053
+ if (opts.agentFiles !== false) {
23054
+ for (const name of AGENT_FILES) {
23055
+ const file2 = join5(root, name);
23056
+ const text = existsSync5(file2) ? readFileSync5(file2, "utf8") : null;
23057
+ if (text === null) {
23058
+ writeFileSync3(file2, `${AGENT_POINTER}
23059
+ `);
23060
+ created.push(name);
23061
+ } else if (text.includes("DEPLOYAI.md")) {
23062
+ kept.push(name);
23063
+ } else {
23064
+ const eol = text.includes("\r\n") ? "\r\n" : "\n";
23065
+ const gap = !text.trim() ? "" : text.endsWith("\n") ? eol : eol + eol;
23066
+ appendFileSync(file2, `${gap}${AGENT_POINTER}${eol}`);
23067
+ updated.push(name);
23068
+ }
23069
+ }
23070
+ }
22988
23071
  ensureDeployaiDir(root);
22989
23072
  const existing = readProject(root);
23073
+ const framework = existing?.framework ?? analyzeProject(root).inspect.framework.id;
22990
23074
  if (existing) {
22991
23075
  kept.push(".deployai/project.json");
22992
23076
  } else {
22993
- const analysis = analyzeProject(root);
22994
- writeProject(root, {
22995
- projectId: null,
22996
- framework: analysis.inspect.framework.id,
22997
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
22998
- });
23077
+ writeProject(root, { projectId: null, framework, createdAt: (/* @__PURE__ */ new Date()).toISOString() });
22999
23078
  created.push(".deployai/project.json");
23000
23079
  }
23001
- return { created, kept };
23080
+ const hasCode = existsSync5(join5(root, "package.json")) || framework !== "unknown";
23081
+ return { created, kept, updated, hasCode };
23002
23082
  }
23003
23083
  function initCommand(root, opts) {
23004
23084
  const res = runInit(root, opts);
@@ -23008,6 +23088,7 @@ function initCommand(root, opts) {
23008
23088
  out(
23009
23089
  rows([
23010
23090
  ...res.created.map((f) => ["Created", f]),
23091
+ ...res.updated.map((f) => ["Added a line", `${f} (read DEPLOYAI.md)`]),
23011
23092
  ...res.kept.map((f) => ["Kept", f]),
23012
23093
  ["Guard", ".deployai/last-check.json (git ignored)"],
23013
23094
  ["Linked project", project?.projectId ?? "none yet"]
@@ -23015,12 +23096,18 @@ function initCommand(root, opts) {
23015
23096
  );
23016
23097
  out();
23017
23098
  out("Next step");
23018
- out(" Run: npx deployai@latest check");
23099
+ if (res.hasCode) {
23100
+ out(" Run: npx deployai@latest check");
23101
+ } else {
23102
+ out(" Start from a sample: npx deployai@latest samples");
23103
+ out(" Or tell your agent what to build, or to review your plan. It follows DEPLOYAI.md.");
23104
+ }
23019
23105
  if (!project?.projectId) out(" Then: npx deployai@latest login, npx deployai@latest link");
23020
23106
  }
23021
23107
 
23022
23108
  // src/commands/check.ts
23023
- import { writeFileSync as writeFileSync4 } from "fs";
23109
+ import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
23110
+ import { join as join6 } from "path";
23024
23111
 
23025
23112
  // src/prompt.ts
23026
23113
  var PROMPT_RULES = [
@@ -23030,8 +23117,10 @@ var PROMPT_RULES = [
23030
23117
  "Keep the project runnable outside DeployAI.",
23031
23118
  "Never add credentials to source code.",
23032
23119
  "Explain every step to the user in simple words, in the language they write to you in.",
23033
- "For the database, use D1 as shown in the DeployAI CRUD sample."
23120
+ "For the database, use D1 as shown in the DeployAI CRUD sample.",
23121
+ "Follow DEPLOYAI.md for every future change. If it is missing, run: npx deployai@latest init"
23034
23122
  ];
23123
+ var DATA_CODES = /* @__PURE__ */ new Set(["fs_write", "unsupported_db_postgres", "unsupported_db_mysql", "unsupported_db_mongodb", "unsupported_db_sqlite_file", "native_module_bcrypt"]);
23035
23124
  var MAX_LOCATIONS = 3;
23036
23125
  function locList(items) {
23037
23126
  const locs = [...new Set(items.map(locationOf).filter(Boolean))];
@@ -23070,6 +23159,11 @@ function buildPrompt(analysis) {
23070
23159
  if (def) lines.push(`- ${def.fixForAgent}`);
23071
23160
  }
23072
23161
  lines.push("");
23162
+ if (blockerGroups.some((g) => DATA_CODES.has(g.code))) {
23163
+ lines.push("Keep existing data:");
23164
+ lines.push(...KEEP_DATA_RULES);
23165
+ lines.push("");
23166
+ }
23073
23167
  lines.push("Rules:");
23074
23168
  for (const r of PROMPT_RULES) lines.push(`- ${r}`);
23075
23169
  lines.push("");
@@ -23219,6 +23313,7 @@ async function runCheck(root, ctx, opts = {}) {
23219
23313
  } else {
23220
23314
  out(t("runDeploy"));
23221
23315
  }
23316
+ if (!existsSync6(join6(root, "DEPLOYAI.md"))) out(t("initHint"));
23222
23317
  }
23223
23318
  await telemetry;
23224
23319
  return a;
@@ -23432,7 +23527,7 @@ async function linkCommand(root, ctx, target, opts) {
23432
23527
  import { createInterface as createInterface2 } from "readline/promises";
23433
23528
 
23434
23529
  // src/tar.ts
23435
- import { readFileSync as readFileSync5 } from "fs";
23530
+ import { readFileSync as readFileSync6 } from "fs";
23436
23531
  import { gzipSync } from "zlib";
23437
23532
  var BLOCK = 512;
23438
23533
  function writeString(buf, offset, length, value) {
@@ -23516,7 +23611,7 @@ function packFiles(files) {
23516
23611
  return createTarGz(
23517
23612
  files.map((f) => ({
23518
23613
  name: f.rel,
23519
- data: readFileSync5(f.abs),
23614
+ data: readFileSync6(f.abs),
23520
23615
  mtimeMs: f.mtimeMs,
23521
23616
  mode: f.mode & 64 ? 493 : 420
23522
23617
  }))
@@ -23719,8 +23814,8 @@ async function claimCommand(root, ctx, opts) {
23719
23814
 
23720
23815
  // src/commands/samples.ts
23721
23816
  import { createInterface as createInterface3 } from "readline/promises";
23722
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync5 } from "fs";
23723
- import { dirname, join as join6, relative, resolve, sep } from "path";
23817
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync5 } from "fs";
23818
+ import { dirname, join as join7, relative, resolve, sep } from "path";
23724
23819
  import { gunzipSync } from "zlib";
23725
23820
  var SAMPLES = [
23726
23821
  { key: "landing", title: "Landing page: a full one-page site with WhatsApp sign-up", stack: "static HTML and CSS" },
@@ -23731,7 +23826,7 @@ var SAMPLES = [
23731
23826
  { key: "admin", title: "Back office with login: dashboard, orders, stock, customers", stack: "Astro on Workers, D1" }
23732
23827
  ];
23733
23828
  var MAX_BYTES = 20 * 1024 * 1024;
23734
- var IGNORED = /* @__PURE__ */ new Set([".git", ".DS_Store", "Thumbs.db", ".deployai"]);
23829
+ var IGNORED = /* @__PURE__ */ new Set([".git", ".DS_Store", "Thumbs.db", ".deployai", "DEPLOYAI.md", "AGENTS.md", "CLAUDE.md"]);
23735
23830
  function listSamples(apiUrl) {
23736
23831
  out("DeployAI samples");
23737
23832
  out("");
@@ -23741,7 +23836,7 @@ function listSamples(apiUrl) {
23741
23836
  out(`See them live: ${apiUrl}/samples`);
23742
23837
  }
23743
23838
  function filesIn(dir) {
23744
- return existsSync6(dir) ? readdirSync3(dir).filter((f) => !IGNORED.has(f)) : [];
23839
+ return existsSync7(dir) ? readdirSync3(dir).filter((f) => !IGNORED.has(f)) : [];
23745
23840
  }
23746
23841
  function freeFolder(cwd, key) {
23747
23842
  for (let n2 = 1; ; n2++) {
@@ -23824,7 +23919,7 @@ async function samplesCommand(cwd, ctx, key, opts = {}) {
23824
23919
  }
23825
23920
  const written = await downloadSample(ctx, sample.key, root);
23826
23921
  const base = resolve(root);
23827
- const hasPackage = existsSync6(join6(base, "package.json"));
23922
+ const hasPackage = existsSync7(join7(base, "package.json"));
23828
23923
  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.`);
23829
23924
  out("");
23830
23925
  const t = messages(base);
@@ -23946,6 +24041,8 @@ async function statusCommand(root, ctx) {
23946
24041
  if (newer?.status === "ready") {
23947
24042
  out();
23948
24043
  out(t("nextStep"));
24044
+ out(t("askOwner", { n: newer.number }));
24045
+ if (s.latest?.preview) out(t("showPreview", { url: s.latest.preview }));
23949
24046
  out(t("promoteReady", { n: newer.number }));
23950
24047
  }
23951
24048
  if (s.latest?.migrationStatus === "waiting") {
@@ -23967,8 +24064,8 @@ async function statusCommand(root, ctx) {
23967
24064
 
23968
24065
  // src/commands/start.ts
23969
24066
  import { spawnSync as spawnSync2 } from "child_process";
23970
- import { existsSync as existsSync7, writeFileSync as writeFileSync6 } from "fs";
23971
- import { join as join7, relative as relative2, resolve as resolve2 } from "path";
24067
+ import { existsSync as existsSync8, writeFileSync as writeFileSync6 } from "fs";
24068
+ import { join as join8, relative as relative2, resolve as resolve2 } from "path";
23972
24069
  var REASONS = { start_not_found: "startNotFound", start_expired: "startExpired", start_used_up: "startUsedUp" };
23973
24070
  var reason = (code) => messages(process.cwd())(REASONS[code] ?? "startNotFound");
23974
24071
  async function fetchStart(ctx, id) {
@@ -24006,19 +24103,20 @@ async function startCommand(cwd, ctx, id, opts = {}) {
24006
24103
  if (sample && !sameSite) {
24007
24104
  const written = await downloadSample(ctx, sample.key, root);
24008
24105
  done.push(t("startDownloaded", { key: sample.key, n: written }));
24009
- if (existsSync7(join7(root, "package.json"))) {
24106
+ if (existsSync8(join8(root, "package.json"))) {
24010
24107
  if (opts.install !== false && install(root)) done.push(t("startInstalled"));
24011
24108
  else steps.unshift({ cmd: "npm install", say: "Installs the sample's packages." });
24012
24109
  }
24013
24110
  }
24014
24111
  if (choices.brief) {
24015
24112
  ensureDeployaiDir(root);
24016
- writeFileSync6(join7(root, BRIEF_FILE), `# The owner's details
24113
+ writeFileSync6(join8(root, BRIEF_FILE), `# The owner's details
24017
24114
 
24018
24115
  ${choices.brief}
24019
24116
  `);
24020
24117
  done.push(t("startBrief", { file: BRIEF_FILE }));
24021
24118
  }
24119
+ if (runInit(root).created.includes("DEPLOYAI.md")) done.push(t("startRules"));
24022
24120
  if (choices.projectId) {
24023
24121
  const before = readProject(root);
24024
24122
  writeProject(root, { ...before ?? {}, projectId: choices.projectId, name: choices.name ?? void 0, slug: choices.slug ?? void 0, createdAt: before?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString() });
@@ -24044,7 +24142,7 @@ ${choices.brief}
24044
24142
  }
24045
24143
 
24046
24144
  // src/commands/addon.ts
24047
- import { readFileSync as readFileSync6 } from "fs";
24145
+ import { readFileSync as readFileSync7 } from "fs";
24048
24146
  import { resolve as resolve3 } from "path";
24049
24147
  function linkedProjectId2(root) {
24050
24148
  const id = readProject(root)?.projectId;
@@ -24125,7 +24223,7 @@ async function addonDoneCommand(root, ctx, runId, opts) {
24125
24223
  let report;
24126
24224
  if (opts.report) {
24127
24225
  try {
24128
- report = JSON.parse(readFileSync6(resolve3(root, opts.report), "utf8"));
24226
+ report = JSON.parse(readFileSync7(resolve3(root, opts.report), "utf8"));
24129
24227
  } catch {
24130
24228
  throw new CliError(`Cannot read the report file ${opts.report} as JSON.`, 1, "usage");
24131
24229
  }
@@ -24221,7 +24319,7 @@ function buildProgram() {
24221
24319
  const g = (cmd) => cmd.optsWithGlobals();
24222
24320
  const root = (cmd) => resolve4(g(cmd).dir ?? process.cwd());
24223
24321
  const ctx = (cmd) => apiContext(g(cmd).api);
24224
- program.command("init").description("create DEPLOYAI.md and .deployai/ guard files").option("--force", "overwrite DEPLOYAI.md").action((opts, cmd) => initCommand(root(cmd), opts));
24322
+ 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));
24225
24323
  program.command("inspect").description("show framework, package manager, language, database, storage").option("--json", "machine readable output").action((opts, cmd) => inspectCommand(root(cmd), opts));
24226
24324
  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) => {
24227
24325
  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.5",
3
+ "version": "0.1.0-beta.7",
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",