entrify-deploy 0.0.0-stage → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,160 @@
1
- # Temporary Holding Version
1
+ # entrify-deploy
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Official CLI for [Entrify](https://entrify.site): deploy any project from the terminal in seconds.
4
+
5
+ Formerly `dropdeploy-cli`. To switch: `npm uninstall -g dropdeploy-cli && npm install -g entrify-deploy`. Your saved login carries over.
6
+
7
+ ```bash
8
+ npm install -g entrify-deploy
9
+ ```
10
+
11
+ This installs the `entrify` command. The older `dropdeploy` command is installed too and does the same thing, so existing scripts keep working.
12
+
13
+ ---
14
+
15
+ ## Quick start
16
+
17
+ ```bash
18
+ # Log in (one time)
19
+ entrify auth login
20
+
21
+ # Deploy from any git repo
22
+ entrify deploy
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Commands
28
+
29
+ ### `entrify auth login`
30
+ Log in to your Entrify account.
31
+
32
+ ```bash
33
+ entrify auth login # interactive login
34
+ entrify auth login --email you@example.com # pre-fill email
35
+ ```
36
+
37
+ Password is always entered interactively; it is never passed as a flag. Logins last 7 days. After that, any command tells you to log in again.
38
+
39
+ ### `entrify auth status`
40
+ Show the currently logged-in account.
41
+
42
+ ### `entrify auth logout`
43
+ Clear saved credentials.
44
+
45
+ ---
46
+
47
+ ### `entrify deploy`
48
+ Trigger a deployment for the current repository.
49
+
50
+ ```bash
51
+ entrify deploy # auto-match project by git remote
52
+ entrify deploy --project-id my-app # deploy to a specific project
53
+ entrify deploy --project-id=my-app # same
54
+ entrify deploy --dir /path/to/repo # use a different directory
55
+ ```
56
+
57
+ Entrify deploys from your **git remote**, not local files. Push your changes before deploying.
58
+
59
+ The project is matched by your `origin` remote, whether it's an HTTPS or SSH URL. If several projects use the same repo, the one on your current branch wins. The server always builds the **project's** branch; the CLI warns you when that isn't the branch you have checked out.
60
+
61
+ During the build, the CLI streams live output:
62
+
63
+ ```
64
+ ▶ Entrify
65
+
66
+ Checking repository… ✓
67
+ Validating project… ✓
68
+ Detecting framework… ✓ NEXTJS (next.config.js)
69
+ Resolving project… ✓ my-app (my-app)
70
+ Triggering deployment… ✓
71
+
72
+ › Cloning repository
73
+ › Building Docker image
74
+ › Starting container
75
+
76
+ ✓ Deployed successfully
77
+
78
+ Live URL → https://my-app.entrify.site
79
+ ```
80
+
81
+ On failure, the last 20 lines of the build log and a probable cause are printed.
82
+
83
+ ---
84
+
85
+ ### `entrify projects`
86
+ List all your projects and their current status.
87
+
88
+ ```
89
+ Your projects:
90
+ my-app My App DEPLOYED
91
+ → https://my-app.entrify.site
92
+
93
+ api-server API Server FAILED
94
+ ```
95
+
96
+ ---
97
+
98
+ ### `entrify help`
99
+ Print the full command reference.
100
+
101
+ ### `entrify --version`
102
+ Print the installed version.
103
+
104
+ ---
105
+
106
+ ## CI / automation
107
+
108
+ Skip interactive login by setting environment variables:
109
+
110
+ ```bash
111
+ export ENTRIFY_TOKEN=your-jwt-token
112
+ export ENTRIFY_URL=https://entrify.site
113
+
114
+ entrify deploy --project-id my-app
115
+ ```
116
+
117
+ `DROPDEPLOY_TOKEN`, `DROPDEPLOY_URL` and `DROPDEPLOY_EMAIL` still work. Without a terminal, the CLI never prompts. If it can't match the repository to a project, it exits with an error asking for `--project-id`.
118
+
119
+ ---
120
+
121
+ ## Supported frameworks
122
+
123
+ Entrify auto-detects your framework from the repository contents:
124
+
125
+ | Framework | Detection |
126
+ |-----------|-----------|
127
+ | Next.js | `next.config.js` / `.ts` / `.mjs` |
128
+ | React (Vite) | `vite.config` + React dependency |
129
+ | Vue (Vite) | `vite.config` + Vue dependency |
130
+ | Svelte | `vite.config` + Svelte dependency |
131
+ | Node.js | `package.json` with `start` script |
132
+ | Django | `manage.py` |
133
+ | FastAPI | `main.py` with `FastAPI()` |
134
+ | Flask | `app.py` with `Flask()` |
135
+ | Go | `go.mod` |
136
+ | Rust | `Cargo.toml` |
137
+ | Java / Spring Boot | `pom.xml` |
138
+ | Static HTML | `index.html` |
139
+
140
+ ---
141
+
142
+ ## Installation
143
+
144
+ Always install globally so the `entrify` command is available system-wide:
145
+
146
+ ```bash
147
+ npm install -g entrify-deploy
148
+ ```
149
+
150
+ Verify the installation:
151
+
152
+ ```bash
153
+ entrify --version
154
+ ```
155
+
156
+ ---
157
+
158
+ ## License
159
+
160
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ import type { Credentials } from './auth.js';
2
+ export interface Project {
3
+ id: string;
4
+ name: string;
5
+ slug: string;
6
+ type: string;
7
+ githubUrl: string | null;
8
+ /** The branch the server builds, whatever is checked out locally. */
9
+ branch?: string;
10
+ deployments?: Array<{
11
+ id: string;
12
+ status: string;
13
+ subdomain: string | null;
14
+ createdAt: string;
15
+ }>;
16
+ }
17
+ export interface DeployResult {
18
+ deploymentId: string;
19
+ message: string;
20
+ queued: boolean;
21
+ }
22
+ export interface DeployStatus {
23
+ status: string;
24
+ buildLog: string | null;
25
+ commitHash: string | null;
26
+ subdomain: string | null;
27
+ }
28
+ export interface DetectResult {
29
+ type: string;
30
+ confidence: 'high' | 'medium' | 'low';
31
+ hint: string;
32
+ }
33
+ export type SseEvent = {
34
+ type: 'line';
35
+ text: string;
36
+ } | {
37
+ type: 'existing';
38
+ log: string;
39
+ } | {
40
+ type: 'done';
41
+ };
42
+ export declare class EntrifyApi {
43
+ private base;
44
+ private token;
45
+ constructor(creds: Credentials);
46
+ private authHeaders;
47
+ private json;
48
+ listProjects(): Promise<Project[]>;
49
+ detectType(repoUrl: string, branch: string): Promise<DetectResult>;
50
+ triggerDeploy(projectId: string): Promise<DeployResult>;
51
+ getDeploymentStatus(projectId: string, deploymentId: string): Promise<DeployStatus>;
52
+ streamLogs(projectId: string, deploymentId: string): AsyncGenerator<SseEvent>;
53
+ }
54
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAQrB,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,EAAE,WAAW;IAK9B,OAAO,CAAC,WAAW;YAOL,IAAI;IAyBZ,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIlC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIlE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIvD,mBAAmB,CACvB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,YAAY,CAAC;IAOjB,UAAU,CACf,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,cAAc,CAAC,QAAQ,CAAC;CAoC5B"}
package/dist/api.js ADDED
@@ -0,0 +1,96 @@
1
+ import { apiErrorMessage, cliName } from './util.js';
2
+ function isSseEvent(x) {
3
+ if (typeof x !== 'object' || x === null)
4
+ return false;
5
+ const t = x.type;
6
+ return t === 'line' || t === 'existing' || t === 'done';
7
+ }
8
+ export class EntrifyApi {
9
+ base;
10
+ token;
11
+ constructor(creds) {
12
+ this.base = creds.apiUrl;
13
+ this.token = creds.token;
14
+ }
15
+ authHeaders() {
16
+ return {
17
+ 'Content-Type': 'application/json',
18
+ Authorization: `Bearer ${this.token}`,
19
+ };
20
+ }
21
+ async json(method, path, body) {
22
+ const controller = new AbortController();
23
+ const timer = setTimeout(() => controller.abort(), 30_000);
24
+ try {
25
+ const res = await fetch(`${this.base}${path}`, {
26
+ method,
27
+ headers: this.authHeaders(),
28
+ body: body !== undefined ? JSON.stringify(body) : undefined,
29
+ signal: controller.signal,
30
+ });
31
+ if (res.status === 401) {
32
+ // CLI logins are JWTs that expire (7 days by default).
33
+ throw new Error(`Your login has expired or is no longer valid. Run: ${cliName()} auth login`);
34
+ }
35
+ if (!res.ok) {
36
+ const body = await res.json().catch(() => null);
37
+ throw new Error(apiErrorMessage(body, `API ${res.status} on ${method} ${path}`));
38
+ }
39
+ const payload = (await res.json());
40
+ return payload.data;
41
+ }
42
+ finally {
43
+ clearTimeout(timer);
44
+ }
45
+ }
46
+ async listProjects() {
47
+ return this.json('GET', '/api/projects');
48
+ }
49
+ async detectType(repoUrl, branch) {
50
+ return this.json('POST', '/api/detect-type', { repoUrl, branch });
51
+ }
52
+ async triggerDeploy(projectId) {
53
+ return this.json('POST', `/api/projects/${projectId}/deploy`);
54
+ }
55
+ async getDeploymentStatus(projectId, deploymentId) {
56
+ return this.json('GET', `/api/projects/${projectId}/deployments/${deploymentId}/logs`);
57
+ }
58
+ async *streamLogs(projectId, deploymentId) {
59
+ const res = await fetch(`${this.base}/api/projects/${projectId}/deployments/${deploymentId}/logs/stream`, { headers: { Authorization: `Bearer ${this.token}` } });
60
+ if (!res.ok || !res.body) {
61
+ throw new Error(`Stream connect failed: ${res.status}`);
62
+ }
63
+ const reader = res.body.getReader();
64
+ const decoder = new TextDecoder();
65
+ let buffer = '';
66
+ try {
67
+ while (true) {
68
+ const { done, value } = await reader.read();
69
+ if (done)
70
+ break;
71
+ buffer += decoder.decode(value, { stream: true });
72
+ const chunks = buffer.split('\n\n');
73
+ buffer = chunks.pop() ?? '';
74
+ for (const chunk of chunks) {
75
+ if (!chunk.startsWith('data: '))
76
+ continue;
77
+ try {
78
+ const raw = JSON.parse(chunk.slice(6));
79
+ if (!isSseEvent(raw))
80
+ continue;
81
+ yield raw;
82
+ if (raw.type === 'done')
83
+ return;
84
+ }
85
+ catch {
86
+ // malformed SSE chunk — skip
87
+ }
88
+ }
89
+ }
90
+ }
91
+ finally {
92
+ reader.cancel().catch(() => { });
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /** Where `entrify auth login` connects unless --api-url says otherwise. */
2
+ export declare const PRODUCTION_URL = "https://entrify.site";
3
+ export interface Credentials {
4
+ token: string;
5
+ email: string;
6
+ apiUrl: string;
7
+ }
8
+ export declare function saveCredentials(creds: Credentials): Promise<void>;
9
+ export declare function readCredentials(): Promise<Credentials | null>;
10
+ export declare function clearCredentials(): Promise<void>;
11
+ export declare function login(apiUrl: string, email: string, password: string): Promise<Credentials>;
12
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAKA,2EAA2E;AAC3E,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAQrD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD,wBAAsB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmBnE;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtD;AAED,wBAAsB,KAAK,CACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAwBtB"}
package/dist/auth.js ADDED
@@ -0,0 +1,74 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { readFile, writeFile, rename, mkdir, unlink } from 'node:fs/promises';
4
+ import { apiErrorMessage } from './util.js';
5
+ /** Where `entrify auth login` connects unless --api-url says otherwise. */
6
+ export const PRODUCTION_URL = 'https://entrify.site';
7
+ // ponytail: the platform moved from app.en3.wtf; drop this once that domain is retired.
8
+ const LEGACY_PRODUCTION_URL = 'https://app.en3.wtf';
9
+ /** Saved logins keep working after the move: same server, same token, new host. */
10
+ const currentUrl = (url) => url.replace(/\/$/, '') === LEGACY_PRODUCTION_URL ? PRODUCTION_URL : url;
11
+ // Kept under the old name so logins saved by earlier versions keep working.
12
+ function configDir() {
13
+ if (process.platform === 'win32' && process.env.APPDATA) {
14
+ return join(process.env.APPDATA, 'dropdeploy');
15
+ }
16
+ return join(homedir(), '.config', 'dropdeploy');
17
+ }
18
+ const credsPath = () => join(configDir(), 'credentials.json');
19
+ export async function saveCredentials(creds) {
20
+ const dir = configDir();
21
+ await mkdir(dir, { recursive: true });
22
+ const tmp = join(dir, '.credentials.tmp');
23
+ await writeFile(tmp, JSON.stringify(creds, null, 2), { mode: 0o600 });
24
+ await rename(tmp, credsPath());
25
+ }
26
+ export async function readCredentials() {
27
+ // Allow overriding via environment variable (useful in CI). The DROPDEPLOY_* names still work.
28
+ const env = process.env;
29
+ const token = env.ENTRIFY_TOKEN ?? env.DROPDEPLOY_TOKEN;
30
+ const url = env.ENTRIFY_URL ?? env.DROPDEPLOY_URL;
31
+ if (token && url) {
32
+ return {
33
+ token,
34
+ email: env.ENTRIFY_EMAIL ?? env.DROPDEPLOY_EMAIL ?? 'env',
35
+ apiUrl: currentUrl(url),
36
+ };
37
+ }
38
+ try {
39
+ const raw = await readFile(credsPath(), 'utf8');
40
+ const creds = JSON.parse(raw);
41
+ return { ...creds, apiUrl: currentUrl(creds.apiUrl) };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ export async function clearCredentials() {
48
+ await unlink(credsPath()).catch(() => { });
49
+ }
50
+ export async function login(apiUrl, email, password) {
51
+ const base = apiUrl.replace(/\/$/, '');
52
+ try {
53
+ const { protocol, hostname } = new URL(base);
54
+ const isLocal = hostname === 'localhost' || hostname.startsWith('127.') || hostname.startsWith('192.168.');
55
+ if (protocol === 'http:' && !isLocal) {
56
+ process.stderr.write('\x1b[33m⚠ Warning: connecting over HTTP — credentials will be sent in plaintext.\x1b[0m\n');
57
+ }
58
+ }
59
+ catch { /* invalid URL will be caught by the fetch below */ }
60
+ const res = await fetch(`${base}/api/auth/token`, {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({ email, password }),
64
+ });
65
+ if (!res.ok) {
66
+ const body = await res.json().catch(() => null);
67
+ throw new Error(apiErrorMessage(body, `Login failed (${res.status})`));
68
+ }
69
+ const { data } = (await res.json());
70
+ const creds = { token: data.token, email: data.email, apiUrl: base };
71
+ await saveCredentials(creds);
72
+ return creds;
73
+ }
74
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,497 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from 'node:readline';
3
+ import { cwd as processCwd } from 'node:process';
4
+ import { readCredentials, clearCredentials, login, PRODUCTION_URL } from './auth.js';
5
+ import { EntrifyApi } from './api.js';
6
+ import { getGitInfo, validateLocal } from './detector.js';
7
+ import { buildDeployUrl, cliName, normaliseRepoUrl, parseArgs } from './util.js';
8
+ /** `entrify` or `dropdeploy`, whichever was typed. */
9
+ const BIN = cliName();
10
+ // ── ANSI colours (no external dep) ──────────────────────────────────────────
11
+ const c = {
12
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
13
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
14
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
15
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
16
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
17
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
18
+ };
19
+ // ── Interactive prompt ───────────────────────────────────────────────────────
20
+ async function prompt(question) {
21
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
22
+ return new Promise((resolve) => {
23
+ rl.question(question, (answer) => {
24
+ rl.close();
25
+ resolve(answer.trim());
26
+ });
27
+ });
28
+ }
29
+ async function promptHidden(question) {
30
+ process.stdout.write(question);
31
+ if (!process.stdin.isTTY) {
32
+ const rl = createInterface({ input: process.stdin });
33
+ return new Promise((resolve) => {
34
+ rl.once('line', (line) => { rl.close(); resolve(line.trim()); });
35
+ });
36
+ }
37
+ return new Promise((resolve, reject) => {
38
+ let password = '';
39
+ const cleanup = () => {
40
+ process.stdin.setRawMode(false);
41
+ process.stdin.pause();
42
+ process.stdin.removeListener('data', onData);
43
+ };
44
+ const onData = (char) => {
45
+ try {
46
+ if (char === '\r' || char === '\n') {
47
+ cleanup();
48
+ process.stdout.write('\n');
49
+ resolve(password);
50
+ }
51
+ else if (char === '\u0003') {
52
+ cleanup();
53
+ process.stdout.write('\n');
54
+ process.exit(0);
55
+ }
56
+ else if (char === '\u007f' || char === '\u0008') {
57
+ password = password.slice(0, -1);
58
+ }
59
+ else {
60
+ password += char;
61
+ }
62
+ }
63
+ catch (e) {
64
+ cleanup();
65
+ reject(e);
66
+ }
67
+ };
68
+ process.stdin.setRawMode(true);
69
+ process.stdin.resume();
70
+ process.stdin.setEncoding('utf8');
71
+ process.stdin.on('data', onData);
72
+ });
73
+ }
74
+ const STEP_PERCENT = {
75
+ CLONING: 20,
76
+ SCANNING: 40,
77
+ BUILDING_IMAGE: 70,
78
+ STARTING_CONTAINER: 90,
79
+ };
80
+ const STEP_LABEL = {
81
+ CLONING: 'Cloning repository',
82
+ SCANNING: 'Scanning packages',
83
+ BUILDING_IMAGE: 'Building Docker image',
84
+ STARTING_CONTAINER: 'Starting container',
85
+ };
86
+ function detectBuildStep(line) {
87
+ if (line.includes('▶ Cloning'))
88
+ return 'CLONING';
89
+ if (line.includes('▶ Scanning'))
90
+ return 'SCANNING';
91
+ if (line.includes('▶ Building image'))
92
+ return 'BUILDING_IMAGE';
93
+ if (line.includes('▶ Starting'))
94
+ return 'STARTING_CONTAINER';
95
+ return null;
96
+ }
97
+ function renderBar(percent, label) {
98
+ const width = 20;
99
+ const filled = Math.round((percent / 100) * width);
100
+ const bar = '█'.repeat(filled) + '░'.repeat(width - filled);
101
+ return ` [${c.cyan(bar)}] ${String(percent).padStart(3)}% ${c.dim(label)}`;
102
+ }
103
+ const isTTY = process.stdout.isTTY ?? false;
104
+ function printProgress(percent, label) {
105
+ if (!isTTY)
106
+ return;
107
+ process.stdout.write('\r' + renderBar(percent, label) + ' ');
108
+ }
109
+ function clearProgress() {
110
+ if (!isTTY)
111
+ return;
112
+ process.stdout.write('\r' + ' '.repeat(72) + '\r');
113
+ }
114
+ // ── Error diagnosis from build log tail ─────────────────────────────────────
115
+ const ERROR_PATTERNS = [
116
+ {
117
+ re: /Cannot find module|Module not found/i,
118
+ cause: 'Missing dependency',
119
+ fix: 'Run `npm install` locally and push your changes',
120
+ },
121
+ {
122
+ re: /ENOENT.*package\.json/i,
123
+ cause: 'package.json not found',
124
+ fix: 'Ensure package.json is committed to the repo',
125
+ },
126
+ {
127
+ re: /Authentication failed|could not read Username/i,
128
+ cause: 'Git authentication failed',
129
+ fix: 'Reconnect your Git provider in Entrify → Settings',
130
+ },
131
+ {
132
+ re: /Blocked package/i,
133
+ cause: 'Blocked package detected',
134
+ fix: 'Remove the flagged package from package.json and push',
135
+ },
136
+ {
137
+ re: /npm ERR!/i,
138
+ cause: 'npm build error',
139
+ fix: 'Run `npm run build` locally to reproduce and debug',
140
+ },
141
+ {
142
+ re: /error TS\d+/i,
143
+ cause: 'TypeScript compile error',
144
+ fix: 'Run `tsc --noEmit` locally to see type errors',
145
+ },
146
+ {
147
+ re: /exit code: 1|exited with code 1/i,
148
+ cause: 'Build script exited with an error',
149
+ fix: 'Run the build command locally to debug the output',
150
+ },
151
+ ];
152
+ function diagnose(log) {
153
+ const tail = log.split('\n').slice(-40).join('\n');
154
+ for (const { re, cause, fix } of ERROR_PATTERNS) {
155
+ if (re.test(tail))
156
+ return { cause, fix };
157
+ }
158
+ return null;
159
+ }
160
+ // ── Project selection ────────────────────────────────────────────────────────
161
+ async function pickProject(api, remoteUrl, localBranch, flagProjectId) {
162
+ const projects = await api.listProjects();
163
+ if (flagProjectId) {
164
+ const p = projects.find((p) => p.id === flagProjectId || p.slug === flagProjectId);
165
+ if (!p)
166
+ throw new Error(`Project "${flagProjectId}" not found`);
167
+ return p;
168
+ }
169
+ // Auto-match by git remote URL (HTTPS or SSH); with several projects on one repo, prefer this branch's
170
+ if (remoteUrl) {
171
+ const needle = normaliseRepoUrl(remoteUrl);
172
+ const matches = projects.filter((p) => p.githubUrl && normaliseRepoUrl(p.githubUrl) === needle);
173
+ if (matches.length > 0)
174
+ return matches.find((p) => p.branch === localBranch) ?? matches[0];
175
+ }
176
+ if (projects.length === 0) {
177
+ throw new Error('No projects found on Entrify. Create one from the dashboard first.');
178
+ }
179
+ // Without a terminal (CI) the prompt below would wait forever.
180
+ if (!process.stdin.isTTY) {
181
+ throw new Error(`No project matches this repository. Pass --project-id <id|slug> (list them with: ${BIN} projects).`);
182
+ }
183
+ // Prompt user to pick
184
+ console.log(`\n${c.bold('Select a project:')}`);
185
+ projects.forEach((p, i) => {
186
+ const latest = p.deployments?.[0];
187
+ const status = latest
188
+ ? latest.status === 'DEPLOYED'
189
+ ? c.green(latest.status)
190
+ : latest.status === 'FAILED'
191
+ ? c.red(latest.status)
192
+ : c.yellow(latest.status)
193
+ : c.dim('no deployments');
194
+ console.log(` ${c.cyan(String(i + 1))}) ${p.name} ${c.dim(`(${p.slug})`)} ${status}`);
195
+ });
196
+ const answer = await prompt(`\nEnter number [1-${projects.length}]: `);
197
+ const idx = parseInt(answer, 10) - 1;
198
+ if (isNaN(idx) || idx < 0 || idx >= projects.length) {
199
+ throw new Error('Invalid selection');
200
+ }
201
+ return projects[idx];
202
+ }
203
+ // ── Commands ─────────────────────────────────────────────────────────────────
204
+ async function cmdAuthLogin(flags) {
205
+ const apiUrl = flags['api-url'] ?? PRODUCTION_URL;
206
+ console.log(`Connecting to ${c.cyan(apiUrl)}`);
207
+ const email = flags['email'] ?? (await prompt('Email: '));
208
+ const password = await promptHidden('Password: ');
209
+ process.stdout.write('Logging in… ');
210
+ const creds = await login(apiUrl, email, password);
211
+ console.log(c.green('✓'));
212
+ console.log(`Logged in as ${c.bold(creds.email)}`);
213
+ }
214
+ async function cmdAuthStatus() {
215
+ const creds = await readCredentials();
216
+ if (!creds) {
217
+ console.log(`${c.yellow('Not logged in.')} Run: ${BIN} auth login`);
218
+ process.exit(1);
219
+ }
220
+ console.log(`${c.green('✓')} Logged in as ${c.bold(creds.email)}`);
221
+ console.log(` API: ${c.dim(creds.apiUrl)}`);
222
+ }
223
+ async function cmdAuthLogout() {
224
+ await clearCredentials();
225
+ console.log(`${c.green('✓')} Logged out`);
226
+ }
227
+ async function cmdProjects() {
228
+ const creds = await readCredentials();
229
+ if (!creds) {
230
+ console.error(c.red('Not logged in.') + ` Run: ${BIN} auth login`);
231
+ process.exit(1);
232
+ }
233
+ const api = new EntrifyApi(creds);
234
+ const projects = await api.listProjects();
235
+ if (projects.length === 0) {
236
+ console.log('No projects found.');
237
+ return;
238
+ }
239
+ console.log(`\n${c.bold('Your projects:')}`);
240
+ for (const p of projects) {
241
+ const latest = p.deployments?.[0];
242
+ const statusStr = latest
243
+ ? latest.status === 'DEPLOYED'
244
+ ? c.green(latest.status)
245
+ : latest.status === 'FAILED'
246
+ ? c.red(latest.status)
247
+ : c.yellow(latest.status)
248
+ : c.dim('no deployments');
249
+ console.log(` ${c.cyan(p.slug)} ${p.name} ${statusStr}`);
250
+ if (latest?.subdomain) {
251
+ console.log(` ${c.dim('→ ' + buildDeployUrl(creds.apiUrl, latest.subdomain))}`);
252
+ }
253
+ }
254
+ console.log();
255
+ }
256
+ async function cmdDeploy(flags) {
257
+ const dir = flags['dir'] ?? processCwd();
258
+ // ── 1. Auth check ──────────────────────────────────────────────────────────
259
+ const creds = await readCredentials();
260
+ if (!creds) {
261
+ console.error(c.red('Not logged in.') + ` Run: ${BIN} auth login`);
262
+ process.exit(1);
263
+ }
264
+ const api = new EntrifyApi(creds);
265
+ console.log(`\n${c.bold('▶ Entrify')}\n`);
266
+ // ── 2. Git info ───────────────────────────────────────────────────────────
267
+ process.stdout.write(' Checking repository… ');
268
+ const gitInfo = await getGitInfo(dir);
269
+ console.log(c.green('✓'));
270
+ if (gitInfo.isDirty) {
271
+ console.log(` ${c.yellow('⚠')} Working tree has uncommitted changes`);
272
+ }
273
+ // ── 3. Validate ───────────────────────────────────────────────────────────
274
+ process.stdout.write(' Validating project… ');
275
+ const validation = await validateLocal(dir, gitInfo);
276
+ if (!validation.ok) {
277
+ console.log(c.red('✗'));
278
+ for (const e of validation.errors) {
279
+ console.error(` ${c.red('✗')} ${e}`);
280
+ }
281
+ process.exit(1);
282
+ }
283
+ console.log(c.green('✓'));
284
+ for (const w of validation.warnings) {
285
+ console.log(` ${c.yellow('⚠')} ${w}`);
286
+ }
287
+ // ── 4. Framework detection ────────────────────────────────────────────────
288
+ if (gitInfo.remoteUrl) {
289
+ process.stdout.write(' Detecting framework… ');
290
+ try {
291
+ const detected = await api.detectType(gitInfo.remoteUrl, gitInfo.branch);
292
+ console.log(`${c.green('✓')} ${c.bold(detected.type)} ${c.dim(`(${detected.hint})`)}`);
293
+ }
294
+ catch {
295
+ console.log(c.dim('skipped'));
296
+ }
297
+ }
298
+ // ── 5. Project resolution ──────────────────────────────────────────────────
299
+ process.stdout.write(' Resolving project… ');
300
+ const project = await pickProject(api, gitInfo.remoteUrl, gitInfo.branch, flags['project-id'] ?? null);
301
+ console.log(`${c.green('✓')} ${c.bold(project.name)} ${c.dim(`(${project.slug})`)}`);
302
+ // The server builds the project's branch, not whatever is checked out here.
303
+ if (project.branch && gitInfo.branch !== 'HEAD' && gitInfo.branch !== project.branch) {
304
+ console.log(` ${c.yellow('⚠')} This project deploys branch ${c.bold(project.branch)}; you are on ${c.bold(gitInfo.branch)}.`);
305
+ }
306
+ // ── 6. Trigger deployment ──────────────────────────────────────────────────
307
+ process.stdout.write(' Triggering deployment… ');
308
+ const { deploymentId, queued } = await api.triggerDeploy(project.id);
309
+ console.log(c.green('✓') + (queued ? c.dim(' (queued behind active build)') : ''));
310
+ console.log();
311
+ // ── 7. Stream logs + live progress bar ────────────────────────────────────
312
+ const logLines = [];
313
+ let currentStep = '';
314
+ let currentPercent = 5;
315
+ printProgress(currentPercent, 'Waiting in queue…');
316
+ try {
317
+ for await (const evt of api.streamLogs(project.id, deploymentId)) {
318
+ if (evt.type === 'line') {
319
+ logLines.push(evt.text);
320
+ const step = detectBuildStep(evt.text);
321
+ if (step) {
322
+ currentStep = step;
323
+ currentPercent = STEP_PERCENT[step];
324
+ clearProgress();
325
+ console.log(`\n ${c.cyan('›')} ${c.bold(STEP_LABEL[step])}`);
326
+ printProgress(currentPercent, STEP_LABEL[step] + '…');
327
+ }
328
+ else {
329
+ clearProgress();
330
+ console.log(` ${c.dim(evt.text)}`);
331
+ printProgress(currentPercent, currentStep ? STEP_LABEL[currentStep] + '…' : 'Building…');
332
+ }
333
+ }
334
+ else if (evt.type === 'existing') {
335
+ for (const l of evt.log.split('\n')) {
336
+ const step = detectBuildStep(l);
337
+ if (step) {
338
+ currentStep = step;
339
+ currentPercent = STEP_PERCENT[step];
340
+ }
341
+ }
342
+ logLines.push(evt.log);
343
+ }
344
+ else if (evt.type === 'done') {
345
+ break;
346
+ }
347
+ }
348
+ }
349
+ catch {
350
+ clearProgress();
351
+ console.log(` ${c.yellow('⚠')} Log stream disconnected — polling for result…`);
352
+ }
353
+ // ── 8. Fetch final status ──────────────────────────────────────────────────
354
+ clearProgress();
355
+ let finalStatus = null;
356
+ let finalLog = null;
357
+ let subdomain = null;
358
+ // SSE ends slightly before DB is updated — poll with exponential backoff
359
+ let consecutiveErrors = 0;
360
+ for (let attempt = 0; attempt < 20; attempt++) {
361
+ const delay = Math.min(1000 * 2 ** attempt, 10_000);
362
+ await new Promise((r) => setTimeout(r, delay));
363
+ try {
364
+ const s = await api.getDeploymentStatus(project.id, deploymentId);
365
+ consecutiveErrors = 0;
366
+ finalLog = s.buildLog;
367
+ subdomain = s.subdomain;
368
+ if (['DEPLOYED', 'FAILED', 'CANCELLED'].includes(s.status)) {
369
+ finalStatus = s.status;
370
+ break;
371
+ }
372
+ }
373
+ catch {
374
+ if (++consecutiveErrors >= 5)
375
+ break;
376
+ }
377
+ }
378
+ // ── 9. Final output ────────────────────────────────────────────────────────
379
+ console.log();
380
+ if (finalStatus === 'DEPLOYED') {
381
+ console.log(c.bold(c.green('✓ Deployed successfully')));
382
+ if (subdomain) {
383
+ const url = buildDeployUrl(creds.apiUrl, subdomain);
384
+ console.log(`\n ${c.bold('Live URL')} → ${c.cyan(url)}`);
385
+ }
386
+ console.log();
387
+ return;
388
+ }
389
+ if (finalStatus === 'FAILED') {
390
+ const stepLabel = currentStep ? ` at: ${c.bold(currentStep)}` : '';
391
+ console.log(c.bold(c.red(`✗ Deployment failed${stepLabel}`)));
392
+ console.log();
393
+ const log = finalLog ?? logLines.join('');
394
+ if (log) {
395
+ const tail = log
396
+ .split('\n')
397
+ .filter(Boolean)
398
+ .slice(-20)
399
+ .join('\n');
400
+ console.log(` ${c.dim('Last 20 lines of build log:')}`);
401
+ console.log(' ' + '─'.repeat(52));
402
+ for (const l of tail.split('\n')) {
403
+ console.log(` ${c.dim(l)}`);
404
+ }
405
+ console.log(' ' + '─'.repeat(52));
406
+ console.log();
407
+ const diagnosis = diagnose(log);
408
+ if (diagnosis) {
409
+ console.log(` ${c.yellow('Probable cause:')} ${diagnosis.cause}`);
410
+ console.log(` ${c.cyan('Suggested fix:')} ${diagnosis.fix}`);
411
+ console.log();
412
+ }
413
+ }
414
+ process.exit(1);
415
+ }
416
+ // Timed out
417
+ console.log(`${c.yellow('⚠')} Timed out waiting for deployment to finish.`);
418
+ console.log(` Check status at: ${c.cyan(`${creds.apiUrl}/projects/${project.id}`)}`);
419
+ process.exit(1);
420
+ }
421
+ // ── Help ─────────────────────────────────────────────────────────────────────
422
+ function cmdHelp() {
423
+ console.log(`
424
+ ${c.bold(BIN)} — Deploy projects to Entrify from the terminal
425
+
426
+ ${c.bold('USAGE')}
427
+ ${BIN} <command> [flags]
428
+
429
+ ${c.bold('COMMANDS')}
430
+ ${c.cyan('deploy')} Deploy the current project ${c.dim('(default)')}
431
+ ${c.dim('--project-id <id|slug>')} Skip project selection and deploy to a specific project
432
+ ${c.dim('--dir <path>')} Use a different working directory
433
+
434
+ ${c.cyan('projects')} List all your projects and their status
435
+
436
+ ${c.cyan('auth login')} Log in to Entrify ${c.dim('(default: entrify.site)')}
437
+ ${c.dim('--api-url <url>')} Override the default URL (e.g. for local dev)
438
+ ${c.dim('--email <email>')} Your email
439
+ ${c.dim('(password is always prompted interactively)')}
440
+ ${c.cyan('auth status')} Show current login status
441
+ ${c.cyan('auth logout')} Clear saved credentials
442
+
443
+ ${c.cyan('help')} Show this help message
444
+ ${c.cyan('--version')} Print the CLI version
445
+
446
+ ${c.bold('ENVIRONMENT')} ${c.dim('(the DROPDEPLOY_* names still work)')}
447
+ ${c.dim('ENTRIFY_TOKEN')} Bearer token ${c.dim('(skips auth login in CI)')}
448
+ ${c.dim('ENTRIFY_URL')} Entrify URL, e.g. https://entrify.site
449
+ ${c.dim('ENTRIFY_EMAIL')} Email ${c.dim('(optional, cosmetic)')}
450
+
451
+ ${c.bold('EXAMPLES')}
452
+ ${c.dim('$')} ${BIN} auth login
453
+ ${c.dim('$')} ${BIN} deploy
454
+ ${c.dim('$')} ${BIN} deploy --project-id my-app
455
+ ${c.dim('$')} ${BIN} projects
456
+ `);
457
+ }
458
+ // ── Entry point ───────────────────────────────────────────────────────────────
459
+ async function main() {
460
+ const { command, flags } = parseArgs(process.argv.slice(2));
461
+ const [cmd, sub] = command;
462
+ if (flags['help'] === 'true')
463
+ return cmdHelp();
464
+ if (cmd === 'version' || flags['version'] === 'true') {
465
+ const { readFile } = await import('node:fs/promises');
466
+ const { join, dirname } = await import('node:path');
467
+ const { fileURLToPath } = await import('node:url');
468
+ const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
469
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
470
+ console.log(pkg.version);
471
+ return;
472
+ }
473
+ if (cmd === 'auth') {
474
+ if (sub === 'login')
475
+ return cmdAuthLogin(flags);
476
+ if (sub === 'status')
477
+ return cmdAuthStatus();
478
+ if (sub === 'logout')
479
+ return cmdAuthLogout();
480
+ console.error('Unknown auth subcommand. Use: login | status | logout');
481
+ process.exit(1);
482
+ }
483
+ if (cmd === 'projects')
484
+ return cmdProjects();
485
+ if (cmd === 'deploy' || cmd === undefined)
486
+ return cmdDeploy(flags);
487
+ if (cmd === 'help' || cmd === '--help' || cmd === '-h')
488
+ return cmdHelp();
489
+ console.error(`Unknown command: ${cmd}`);
490
+ console.error(`Run ${BIN} help for usage.`);
491
+ process.exit(1);
492
+ }
493
+ main().catch((err) => {
494
+ console.error(`\n${c.red('Error:')} ${err.message}`);
495
+ process.exit(1);
496
+ });
497
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface GitInfo {
2
+ remoteUrl: string | null;
3
+ branch: string;
4
+ isDirty: boolean;
5
+ unpushedCommits: boolean;
6
+ }
7
+ export declare function getGitInfo(cwd: string): Promise<GitInfo>;
8
+ export interface ValidationResult {
9
+ ok: boolean;
10
+ errors: string[];
11
+ warnings: string[];
12
+ }
13
+ export declare function validateLocal(cwd: string, info: GitInfo): Promise<ValidationResult>;
14
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,gBAAgB,CAAC,CA6B3B"}
@@ -0,0 +1,47 @@
1
+ import { exec } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ const run = promisify(exec);
6
+ export async function getGitInfo(cwd) {
7
+ const git = (cmd) => run(cmd, { cwd })
8
+ .then(({ stdout }) => stdout.trim())
9
+ .catch(() => null);
10
+ const [remoteUrl, branch, dirty, unpushed] = await Promise.all([
11
+ git('git remote get-url origin'),
12
+ git('git rev-parse --abbrev-ref HEAD'),
13
+ git('git status --porcelain'),
14
+ git('git log @{u}..HEAD --oneline'),
15
+ ]);
16
+ return {
17
+ remoteUrl: remoteUrl || null,
18
+ branch: branch || 'main',
19
+ isDirty: (dirty ?? '').length > 0,
20
+ // null means the command failed (no upstream tracking branch) — treat as unknown, not "has unpushed commits"
21
+ unpushedCommits: unpushed !== null && unpushed.length > 0,
22
+ };
23
+ }
24
+ export async function validateLocal(cwd, info) {
25
+ const errors = [];
26
+ const warnings = [];
27
+ if (!info.remoteUrl) {
28
+ errors.push('No git remote "origin" found. Push your repo to GitHub or GitLab first.');
29
+ }
30
+ if (info.unpushedCommits) {
31
+ warnings.push('You have unpushed commits. Entrify deploys from the remote — push first to include latest changes.');
32
+ }
33
+ // JS projects need something to run: a "build" (Next.js, Vite) or a "start" (Node.js,
34
+ // where the server's build step is --if-present).
35
+ try {
36
+ const raw = await readFile(join(cwd, 'package.json'), 'utf8');
37
+ const pkg = JSON.parse(raw);
38
+ if (!pkg.scripts?.build && !pkg.scripts?.start) {
39
+ errors.push('package.json has neither a "build" nor a "start" script.');
40
+ }
41
+ }
42
+ catch {
43
+ // Not a JS project — skip
44
+ }
45
+ return { ok: errors.length === 0, errors, warnings };
46
+ }
47
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAS5B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAC1B,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC;SACd,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;SACnC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAEvB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7D,GAAG,CAAC,2BAA2B,CAAC;QAChC,GAAG,CAAC,iCAAiC,CAAC;QACtC,GAAG,CAAC,wBAAwB,CAAC;QAC7B,GAAG,CAAC,8BAA8B,CAAC;KACpC,CAAC,CAAC;IAEH,OAAO;QACL,SAAS,EAAE,SAAS,IAAI,IAAI;QAC5B,MAAM,EAAE,MAAM,IAAI,MAAM;QACxB,OAAO,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;QACjC,6GAA6G;QAC7G,eAAe,EAAE,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;KAC1D,CAAC;AACJ,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAa;IAEb,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,CAAC,IAAI,CACT,yEAAyE,CAC1E,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CACX,oGAAoG,CACrG,CAAC;IACJ,CAAC;IAED,sFAAsF;IACtF,kDAAkD;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyC,CAAC;QACpE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACvD,CAAC"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The command the user typed, so hints match it: the package installs both
3
+ * `entrify` and the older `dropdeploy`.
4
+ */
5
+ export declare function cliName(argv1?: string | undefined): string;
6
+ /**
7
+ * Reduces a repository URL to `host/owner/repo`, so the HTTPS URL a project
8
+ * stores matches an SSH remote such as `git@github.com:owner/repo.git`.
9
+ */
10
+ export declare function normaliseRepoUrl(url: string): string;
11
+ /** The message from an API error body: `{ error: { message } }`, `{ error }` or `{ message }`. */
12
+ export declare function apiErrorMessage(body: unknown, fallback: string): string;
13
+ /** A deployed project's address. Local dev serves projects through the app's proxy route. */
14
+ export declare function buildDeployUrl(apiUrl: string, subdomain: string): string;
15
+ /** Splits argv into positional words and `--flag value` / `--flag=value` / bare `--flag` flags. */
16
+ export declare function parseArgs(argv: string[]): {
17
+ command: string[];
18
+ flags: Record<string, string>;
19
+ };
20
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,GAAE,MAAM,GAAG,SAA2B,GAAG,MAAM,CAE3E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUvE;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUxE;AAED,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAsB9F"}
package/dist/util.js ADDED
@@ -0,0 +1,81 @@
1
+ import { basename } from 'node:path';
2
+ /**
3
+ * The command the user typed, so hints match it: the package installs both
4
+ * `entrify` and the older `dropdeploy`.
5
+ */
6
+ export function cliName(argv1 = process.argv[1]) {
7
+ return basename(argv1 ?? '') === 'dropdeploy' ? 'dropdeploy' : 'entrify';
8
+ }
9
+ /**
10
+ * Reduces a repository URL to `host/owner/repo`, so the HTTPS URL a project
11
+ * stores matches an SSH remote such as `git@github.com:owner/repo.git`.
12
+ */
13
+ export function normaliseRepoUrl(url) {
14
+ return url
15
+ .trim()
16
+ .toLowerCase()
17
+ .replace(/^[a-z+]+:\/\//, '') // https://, ssh://, git+ssh://
18
+ .replace(/^[^@/]+@/, '') // git@ or user:token@
19
+ .replace(/^([^/:]+):(?!\d+\/)/, '$1/') // scp-style host:owner/repo
20
+ .replace(/^([^/:]+):\d+\//, '$1/') // host:port/
21
+ .replace(/\/+$/, '')
22
+ .replace(/\.git$/, '');
23
+ }
24
+ /** The message from an API error body: `{ error: { message } }`, `{ error }` or `{ message }`. */
25
+ export function apiErrorMessage(body, fallback) {
26
+ if (typeof body !== 'object' || body === null)
27
+ return fallback;
28
+ const { error, message } = body;
29
+ if (typeof error === 'object' && error !== null) {
30
+ const nested = error.message;
31
+ if (typeof nested === 'string' && nested)
32
+ return nested;
33
+ }
34
+ if (typeof error === 'string' && error)
35
+ return error;
36
+ if (typeof message === 'string' && message)
37
+ return message;
38
+ return fallback;
39
+ }
40
+ /** A deployed project's address. Local dev serves projects through the app's proxy route. */
41
+ export function buildDeployUrl(apiUrl, subdomain) {
42
+ try {
43
+ const u = new URL(apiUrl);
44
+ if (u.hostname === 'localhost' || u.hostname.startsWith('127.')) {
45
+ return `${u.origin}/api/proxy/${subdomain}`;
46
+ }
47
+ return `${u.protocol}//${subdomain}.${u.hostname}`;
48
+ }
49
+ catch {
50
+ return `${apiUrl.replace(/\/$/, '')}/api/proxy/${subdomain}`;
51
+ }
52
+ }
53
+ /** Splits argv into positional words and `--flag value` / `--flag=value` / bare `--flag` flags. */
54
+ export function parseArgs(argv) {
55
+ const command = [];
56
+ const flags = {};
57
+ for (let i = 0; i < argv.length; i++) {
58
+ const arg = argv[i];
59
+ if (arg.startsWith('--')) {
60
+ const eq = arg.indexOf('=');
61
+ if (eq > 2) {
62
+ flags[arg.slice(2, eq)] = arg.slice(eq + 1);
63
+ }
64
+ else {
65
+ const next = argv[i + 1];
66
+ flags[arg.slice(2)] = next !== undefined && !next.startsWith('-') ? argv[++i] : 'true';
67
+ }
68
+ }
69
+ else if (arg === '-v') {
70
+ flags['version'] = 'true';
71
+ }
72
+ else if (arg === '-h') {
73
+ flags['help'] = 'true';
74
+ }
75
+ else {
76
+ command.push(arg);
77
+ }
78
+ }
79
+ return { command, flags };
80
+ }
81
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "entrify-deploy",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.2.0",
4
+ "description": "Deploy to Entrify from the terminal or with the Claude Code /deploy skill",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/kpndevrootentri/entrify-cli.git"
8
+ },
9
+ "type": "module",
10
+ "bin": {
11
+ "entrify": "dist/cli.js",
12
+ "dropdeploy": "dist/cli.js"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc && chmod +x dist/cli.js",
22
+ "dev": "tsx src/cli.ts",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepublishOnly": "npm run build",
25
+ "test": "node --import tsx --test src/*.test.ts"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.0.0",
29
+ "tsx": "^4.19.0",
30
+ "typescript": "^5.7.0"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ }
35
+ }