deployai 0.1.0-beta.4 → 0.1.0-beta.6

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 +48 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -49,7 +49,7 @@ Node 20 or newer. No other setup: the CLI talks to https://deployai.co.il.
49
49
  | `deployai versions` | Lists versions: number, live or not, status ("replaced by a newer upload" for one that never built), date, size, message, and a dashboard link when its SQL waits for approval. |
50
50
  | `deployai rollback v5` | Puts version 5 back live, with no rebuild. |
51
51
  | `deployai promote v5` | Puts version 5 live. |
52
- | `deployai status` | Site state, address, live version and queue. |
52
+ | `deployai status` | Site state, address, live version, the newest version when it is not live yet (with the promote command once it is ready), and queue. |
53
53
  | `deployai deploy --guest` | No login needed: puts the site live as a temporary site with a claim link. More below. |
54
54
  | `deployai pull` | Downloads the code of the linked site's live version into this empty folder. Needs login. |
55
55
  | `deployai claim` | Prints this folder's temporary site keep link again. `--email <address>` mails it, with a reminder before the delete. |
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"] },
@@ -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." },
@@ -21824,20 +21843,24 @@ var M = {
21824
21843
  statusTitle: "DeployAI status",
21825
21844
  state: "State",
21826
21845
  liveVersion: "Live version",
21846
+ newestVersion: "Newest version",
21847
+ promoteReady: " After the owner approves the preview: npx deployai@latest promote v{n} (to put it live)",
21848
+ askOwner: ' Version {n} is ready and not live. Ask the owner: "Version {n} is ready. Do you want to put it live?"',
21849
+ showPreview: " Send them the preview first: {url}",
21827
21850
  notPublished: "not published yet",
21828
21851
  none: "none",
21829
21852
  buildingNow: "building now",
21830
21853
  idle: "idle",
21831
21854
  envListTitle: "Variables",
21832
- envNone: "This site has no variables yet. Add one: npx deployai@latest env set <key> <value>",
21855
+ envNone: "This site has no variables yet. Add one: npx deployai@latest env set <KEY> <value>",
21833
21856
  envSecret: "secret",
21834
21857
  envPlain: "plain",
21835
- envNeedValue: 'Give the value after the key, or pipe it in: echo "<value>" | npx deployai@latest env set <key>',
21858
+ envNeedValue: 'Give the value after the key, or pipe it in: echo "<value>" | npx deployai@latest env set <KEY>',
21836
21859
  envSavedSecret: "Saved {key} as a secret on the live site. Its value is not stored and is never shown again.",
21837
21860
  envSavedPlain: "Saved {key}. The live site gets it in about a minute.",
21838
21861
  envRemoved: "Removed {key}. The live site loses it in about a minute.",
21839
21862
  guestNoEnv: "A temporary site has no environment variables. Keep it in an account first: npx deployai@latest claim",
21840
- envInvalidKey: "A variable name is English letters, digits and _, does not start with a digit, up to 64 characters.",
21863
+ envInvalidKey: "A variable name is capital English letters, digits and _, starts with a letter, up to 64 characters, like STRIPE_KEY.",
21841
21864
  envTooLong: "The value is over 5 KB, too long for a variable.",
21842
21865
  envSendFailed: "The secret did not reach the site. Try again in a minute.",
21843
21866
  envNoKey: "This site has no variable with that name. See them: npx deployai@latest env list",
@@ -21989,20 +22012,24 @@ var M = {
21989
22012
  statusTitle: "DeployAI status",
21990
22013
  state: "\u05DE\u05E6\u05D1",
21991
22014
  liveVersion: "\u05D2\u05E8\u05E1\u05D4 \u05D7\u05D9\u05D4",
22015
+ newestVersion: "\u05D2\u05E8\u05E1\u05D4 \u05D0\u05D7\u05E8\u05D5\u05E0\u05D4",
22016
+ 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)",
22017
+ 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?"',
22018
+ 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}",
21992
22019
  notPublished: "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DC\u05D0 \u05D1\u05D0\u05D5\u05D5\u05D9\u05E8",
21993
22020
  none: "\u05D0\u05D9\u05DF",
21994
22021
  buildingNow: "\u05D1\u05D5\u05E0\u05D9\u05DD \u05E2\u05DB\u05E9\u05D9\u05D5",
21995
22022
  idle: "\u05E4\u05E0\u05D5\u05D9",
21996
22023
  envListTitle: "\u05DE\u05E9\u05EA\u05E0\u05D9\u05DD",
21997
- 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>",
22024
+ 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>",
21998
22025
  envSecret: "\u05E1\u05D5\u05D3",
21999
22026
  envPlain: "\u05D2\u05DC\u05D5\u05D9",
22000
- 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>',
22027
+ 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>',
22001
22028
  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.",
22002
22029
  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.",
22003
22030
  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.",
22004
22031
  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",
22005
- 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.",
22032
+ 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.",
22006
22033
  envTooLong: "\u05D4\u05E2\u05E8\u05DA \u05D2\u05D3\u05D5\u05DC \u05DE\u05BE5KB, \u05D0\u05E8\u05D5\u05DA \u05DE\u05D3\u05D9 \u05DC\u05DE\u05E9\u05EA\u05E0\u05D4.",
22007
22034
  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.",
22008
22035
  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",
@@ -22105,7 +22132,7 @@ function messages(root) {
22105
22132
  }
22106
22133
 
22107
22134
  // src/version.ts
22108
- var CLI_VERSION = "0.1.0-beta.4";
22135
+ var CLI_VERSION = "0.1.0-beta.6";
22109
22136
 
22110
22137
  // src/api.ts
22111
22138
  function apiContext(apiFlag) {
@@ -23925,6 +23952,7 @@ async function statusCommand(root, ctx) {
23925
23952
  const s = await apiRequest(ctx, `/api/cli/status?projectId=${encodeURIComponent(projectId)}`, StatusResponse);
23926
23953
  const p = s.project;
23927
23954
  const t = messages(root);
23955
+ const newer = s.latest && s.latest.number !== p.liveVersion ? s.latest : null;
23928
23956
  out(t("statusTitle"));
23929
23957
  out();
23930
23958
  out(
@@ -23933,9 +23961,18 @@ async function statusCommand(root, ctx) {
23933
23961
  [t("state"), stateName(p.status, root)],
23934
23962
  [t("address"), p.url ?? t("notPublished")],
23935
23963
  [t("liveVersion"), p.liveVersion ? `v${p.liveVersion}` : t("none")],
23964
+ // A newer upload than the live one: its state, so "follow the build" after deploy has something to follow.
23965
+ ...newer ? [[t("newestVersion"), `v${newer.number} ${stateName(newer.status, root)}`]] : [],
23936
23966
  [t("queue"), s.queue.running ? t("buildingNow") : s.queue.position > 0 ? queueText(s.queue.position, root) : t("idle")]
23937
23967
  ])
23938
23968
  );
23969
+ if (newer?.status === "ready") {
23970
+ out();
23971
+ out(t("nextStep"));
23972
+ out(t("askOwner", { n: newer.number }));
23973
+ if (s.latest?.preview) out(t("showPreview", { url: s.latest.preview }));
23974
+ out(t("promoteReady", { n: newer.number }));
23975
+ }
23939
23976
  if (s.latest?.migrationStatus === "waiting") {
23940
23977
  out();
23941
23978
  out(t("sqlWaitingLine", { url: versionsPage(ctx, projectId) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deployai",
3
- "version": "0.1.0-beta.4",
3
+ "version": "0.1.0-beta.6",
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",