gazill 1.0.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.
Files changed (47) hide show
  1. package/dist/commands/login.d.ts +2 -0
  2. package/dist/commands/login.d.ts.map +1 -0
  3. package/dist/commands/login.js +74 -0
  4. package/dist/commands/login.js.map +1 -0
  5. package/dist/commands/logout.d.ts +2 -0
  6. package/dist/commands/logout.d.ts.map +1 -0
  7. package/dist/commands/logout.js +13 -0
  8. package/dist/commands/logout.js.map +1 -0
  9. package/dist/commands/logs.d.ts +2 -0
  10. package/dist/commands/logs.d.ts.map +1 -0
  11. package/dist/commands/logs.js +74 -0
  12. package/dist/commands/logs.js.map +1 -0
  13. package/dist/commands/new.d.ts +3 -0
  14. package/dist/commands/new.d.ts.map +1 -0
  15. package/dist/commands/new.js +126 -0
  16. package/dist/commands/new.js.map +1 -0
  17. package/dist/commands/status.d.ts +2 -0
  18. package/dist/commands/status.d.ts.map +1 -0
  19. package/dist/commands/status.js +51 -0
  20. package/dist/commands/status.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +39 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/lib/api.d.ts +13 -0
  26. package/dist/lib/api.d.ts.map +1 -0
  27. package/dist/lib/api.js +75 -0
  28. package/dist/lib/api.js.map +1 -0
  29. package/dist/lib/config.d.ts +9 -0
  30. package/dist/lib/config.d.ts.map +1 -0
  31. package/dist/lib/config.js +70 -0
  32. package/dist/lib/config.js.map +1 -0
  33. package/dist/lib/watcher.d.ts +11 -0
  34. package/dist/lib/watcher.d.ts.map +1 -0
  35. package/dist/lib/watcher.js +154 -0
  36. package/dist/lib/watcher.js.map +1 -0
  37. package/package.json +35 -0
  38. package/src/commands/login.ts +90 -0
  39. package/src/commands/logout.ts +15 -0
  40. package/src/commands/logs.ts +90 -0
  41. package/src/commands/new.ts +162 -0
  42. package/src/commands/status.ts +70 -0
  43. package/src/index.ts +48 -0
  44. package/src/lib/api.ts +104 -0
  45. package/src/lib/config.ts +75 -0
  46. package/src/lib/watcher.ts +181 -0
  47. package/tsconfig.json +8 -0
@@ -0,0 +1,70 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { API_BASE_URL } from '@gazill/shared';
5
+ const CONFIG_DIR = path.join(os.homedir(), '.gazill');
6
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
7
+ const AUTH_FILE = path.join(CONFIG_DIR, 'auth.json');
8
+ // Ensure config directory exists
9
+ async function ensureConfigDir() {
10
+ try {
11
+ await fs.mkdir(CONFIG_DIR, { recursive: true });
12
+ }
13
+ catch {
14
+ // Directory might already exist
15
+ }
16
+ }
17
+ // Get CLI configuration
18
+ export async function getConfig() {
19
+ try {
20
+ const content = await fs.readFile(CONFIG_FILE, 'utf-8');
21
+ return JSON.parse(content);
22
+ }
23
+ catch {
24
+ return {
25
+ apiUrl: API_BASE_URL,
26
+ };
27
+ }
28
+ }
29
+ // Save CLI configuration
30
+ export async function saveConfig(config) {
31
+ await ensureConfigDir();
32
+ await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
33
+ }
34
+ // Get authentication info
35
+ export async function getAuth() {
36
+ try {
37
+ const content = await fs.readFile(AUTH_FILE, 'utf-8');
38
+ return JSON.parse(content);
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ // Save authentication info
45
+ export async function saveAuth(auth) {
46
+ await ensureConfigDir();
47
+ await fs.writeFile(AUTH_FILE, JSON.stringify(auth, null, 2), {
48
+ mode: 0o600, // Read/write for owner only
49
+ });
50
+ }
51
+ // Clear authentication info
52
+ export async function clearAuth() {
53
+ try {
54
+ await fs.unlink(AUTH_FILE);
55
+ }
56
+ catch {
57
+ // File might not exist
58
+ }
59
+ }
60
+ // Check if user is authenticated
61
+ export async function isAuthenticated() {
62
+ const auth = await getAuth();
63
+ return auth !== null && !!auth.token;
64
+ }
65
+ // Get API URL
66
+ export async function getApiUrl() {
67
+ const config = await getConfig();
68
+ return config.apiUrl;
69
+ }
70
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACtD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAErD,iCAAiC;AACjC,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC;AAED,wBAAwB;AACxB,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,YAAY;SACrB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB;IAChD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED,0BAA0B;AAC1B,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,2BAA2B;AAC3B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAa;IAC1C,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC3D,IAAI,EAAE,KAAK,EAAE,4BAA4B;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,4BAA4B;AAC5B,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;AACH,CAAC;AAED,iCAAiC;AACjC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;IAC7B,OAAO,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACvC,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import chokidar from 'chokidar';
2
+ import type { DeployFile } from '@gazill/shared';
3
+ interface WatcherOptions {
4
+ projectId: string;
5
+ projectDir: string;
6
+ onDeploy?: (files: DeployFile[]) => void;
7
+ onError?: (error: Error) => void;
8
+ }
9
+ export declare function startWatcher(options: WatcherOptions): Promise<chokidar.FSWatcher>;
10
+ export {};
11
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/lib/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAMhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAmBjD,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAoJvF"}
@@ -0,0 +1,154 @@
1
+ import chokidar from 'chokidar';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import debounce from 'lodash/debounce.js';
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import { DEPLOY_DEBOUNCE_MS, MAX_FILE_SIZE_BYTES } from '@gazill/shared';
8
+ import { deploy } from './api.js';
9
+ const IGNORED_PATTERNS = [
10
+ /(^|[/\\])\../, // dotfiles
11
+ 'node_modules/**',
12
+ '.git/**',
13
+ '*.log',
14
+ '.gazill/**',
15
+ 'dist/**',
16
+ 'build/**',
17
+ '__pycache__/**',
18
+ '*.pyc',
19
+ '.env',
20
+ '.env.*',
21
+ 'Dockerfile',
22
+ ];
23
+ export async function startWatcher(options) {
24
+ const { projectId, projectDir, onDeploy, onError } = options;
25
+ const changedFiles = new Set();
26
+ let isDeploying = false;
27
+ // Collect all files for initial deploy
28
+ async function collectAllFiles() {
29
+ const files = [];
30
+ async function walkDir(dir) {
31
+ const entries = await fs.readdir(dir, { withFileTypes: true });
32
+ for (const entry of entries) {
33
+ const fullPath = path.join(dir, entry.name);
34
+ const relativePath = path.relative(projectDir, fullPath);
35
+ // Skip ignored patterns
36
+ if (IGNORED_PATTERNS.some((pattern) => {
37
+ if (typeof pattern === 'string') {
38
+ return relativePath.includes(pattern.replace('/**', ''));
39
+ }
40
+ return pattern.test(relativePath);
41
+ })) {
42
+ continue;
43
+ }
44
+ if (entry.isDirectory()) {
45
+ await walkDir(fullPath);
46
+ }
47
+ else if (entry.isFile()) {
48
+ try {
49
+ const stats = await fs.stat(fullPath);
50
+ if (stats.size <= MAX_FILE_SIZE_BYTES) {
51
+ const content = await fs.readFile(fullPath, 'utf-8');
52
+ files.push({ path: relativePath, content });
53
+ }
54
+ }
55
+ catch {
56
+ // Skip files that can't be read
57
+ }
58
+ }
59
+ }
60
+ }
61
+ await walkDir(projectDir);
62
+ return files;
63
+ }
64
+ // Deploy changed files
65
+ const doDeploy = debounce(async () => {
66
+ if (isDeploying || changedFiles.size === 0)
67
+ return;
68
+ isDeploying = true;
69
+ const filesToDeploy = Array.from(changedFiles);
70
+ changedFiles.clear();
71
+ const spinner = ora('Deploying changes...').start();
72
+ try {
73
+ const files = [];
74
+ for (const filePath of filesToDeploy) {
75
+ const fullPath = path.join(projectDir, filePath);
76
+ try {
77
+ const stats = await fs.stat(fullPath);
78
+ if (stats.size <= MAX_FILE_SIZE_BYTES) {
79
+ const content = await fs.readFile(fullPath, 'utf-8');
80
+ files.push({ path: filePath, content });
81
+ }
82
+ }
83
+ catch {
84
+ // File might have been deleted
85
+ }
86
+ }
87
+ if (files.length > 0) {
88
+ const result = await deploy(projectId, files);
89
+ spinner.succeed(chalk.green(`Deployed ${files.length} file(s) - ${result.url}`));
90
+ onDeploy?.(files);
91
+ }
92
+ else {
93
+ spinner.info('No files to deploy');
94
+ }
95
+ }
96
+ catch (error) {
97
+ const message = error instanceof Error ? error.message : 'Deploy failed';
98
+ spinner.fail(chalk.red(message));
99
+ onError?.(error instanceof Error ? error : new Error(message));
100
+ }
101
+ finally {
102
+ isDeploying = false;
103
+ }
104
+ }, DEPLOY_DEBOUNCE_MS);
105
+ // Create watcher
106
+ const watcher = chokidar.watch(projectDir, {
107
+ ignored: IGNORED_PATTERNS,
108
+ persistent: true,
109
+ ignoreInitial: true,
110
+ awaitWriteFinish: {
111
+ stabilityThreshold: 100,
112
+ pollInterval: 50,
113
+ },
114
+ });
115
+ // Handle file changes
116
+ watcher.on('add', (filePath) => {
117
+ const relativePath = path.relative(projectDir, filePath);
118
+ console.log(chalk.gray(`+ ${relativePath}`));
119
+ changedFiles.add(relativePath);
120
+ doDeploy();
121
+ });
122
+ watcher.on('change', (filePath) => {
123
+ const relativePath = path.relative(projectDir, filePath);
124
+ console.log(chalk.gray(`~ ${relativePath}`));
125
+ changedFiles.add(relativePath);
126
+ doDeploy();
127
+ });
128
+ watcher.on('unlink', (filePath) => {
129
+ const relativePath = path.relative(projectDir, filePath);
130
+ console.log(chalk.gray(`- ${relativePath}`));
131
+ // Note: File deletion isn't fully handled - would need separate API endpoint
132
+ });
133
+ watcher.on('error', (error) => {
134
+ console.error(chalk.red('Watcher error:'), error);
135
+ onError?.(error);
136
+ });
137
+ // Initial deploy of all files
138
+ console.log(chalk.blue('Scanning files...'));
139
+ const allFiles = await collectAllFiles();
140
+ if (allFiles.length > 0) {
141
+ const spinner = ora(`Deploying ${allFiles.length} files...`).start();
142
+ try {
143
+ const result = await deploy(projectId, allFiles);
144
+ spinner.succeed(chalk.green(`Initial deploy complete - ${result.url}`));
145
+ }
146
+ catch (error) {
147
+ const message = error instanceof Error ? error.message : 'Deploy failed';
148
+ spinner.fail(chalk.red(message));
149
+ }
150
+ }
151
+ console.log(chalk.blue('\nWatching for changes... (Ctrl+C to stop)\n'));
152
+ return watcher;
153
+ }
154
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/lib/watcher.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "gazill",
3
+ "version": "1.0.0",
4
+ "description": "CLI for Gazill auto-deploy platform",
5
+ "type": "module",
6
+ "bin": {
7
+ "gazill": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "scripts": {
11
+ "dev": "tsx watch src/index.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/index.js",
14
+ "lint": "tsc --noEmit"
15
+ },
16
+ "keywords": ["cli", "deploy", "docker", "gazill"],
17
+ "author": "",
18
+ "license": "MIT",
19
+ "dependencies": {
20
+ "@gazill/shared": "workspace:*",
21
+ "chalk": "^5.3.0",
22
+ "chokidar": "^3.6.0",
23
+ "commander": "^12.0.0",
24
+ "inquirer": "^9.2.0",
25
+ "lodash": "^4.17.21",
26
+ "ora": "^8.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/inquirer": "^9.0.7",
30
+ "@types/lodash": "^4.14.202",
31
+ "@types/node": "^20.0.0",
32
+ "tsx": "^4.7.0",
33
+ "typescript": "^5.4.0"
34
+ }
35
+ }
@@ -0,0 +1,90 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { signin, signup } from '../lib/api.js';
5
+ import { saveAuth, isAuthenticated, getAuth } from '../lib/config.js';
6
+
7
+ export async function loginCommand(): Promise<void> {
8
+ // Check if already authenticated
9
+ if (await isAuthenticated()) {
10
+ const auth = await getAuth();
11
+ console.log(chalk.yellow(`Already logged in as ${auth?.email}`));
12
+ console.log(chalk.gray('Run "gazill logout" to switch accounts.'));
13
+ return;
14
+ }
15
+
16
+ // Ask for action
17
+ const { action } = await inquirer.prompt<{ action: 'signin' | 'signup' }>([
18
+ {
19
+ type: 'list',
20
+ name: 'action',
21
+ message: 'What would you like to do?',
22
+ choices: [
23
+ { name: 'Sign in to existing account', value: 'signin' },
24
+ { name: 'Create a new account', value: 'signup' },
25
+ ],
26
+ },
27
+ ]);
28
+
29
+ // Get credentials
30
+ const { email, password } = await inquirer.prompt<{
31
+ email: string;
32
+ password: string;
33
+ }>([
34
+ {
35
+ type: 'input',
36
+ name: 'email',
37
+ message: 'Email:',
38
+ validate: (input: string) => {
39
+ if (!input || !input.includes('@')) {
40
+ return 'Please enter a valid email address';
41
+ }
42
+ return true;
43
+ },
44
+ },
45
+ {
46
+ type: 'password',
47
+ name: 'password',
48
+ message: 'Password:',
49
+ mask: '*',
50
+ validate: (input: string) => {
51
+ if (!input || input.length < 8) {
52
+ return 'Password must be at least 8 characters';
53
+ }
54
+ return true;
55
+ },
56
+ },
57
+ ]);
58
+
59
+ const spinner = ora(
60
+ action === 'signup' ? 'Creating account...' : 'Signing in...'
61
+ ).start();
62
+
63
+ try {
64
+ const response =
65
+ action === 'signup'
66
+ ? await signup(email, password)
67
+ : await signin(email, password);
68
+
69
+ // Save auth token
70
+ await saveAuth({
71
+ token: response.token,
72
+ email: response.user.email,
73
+ });
74
+
75
+ spinner.succeed(
76
+ chalk.green(
77
+ action === 'signup'
78
+ ? 'Account created successfully!'
79
+ : 'Signed in successfully!'
80
+ )
81
+ );
82
+
83
+ console.log(chalk.blue(`\nWelcome, ${response.user.email}!`));
84
+ console.log(chalk.gray('Run "gazill new <project-name>" to create a project.'));
85
+ } catch (error) {
86
+ const message = error instanceof Error ? error.message : 'Authentication failed';
87
+ spinner.fail(chalk.red(message));
88
+ process.exit(1);
89
+ }
90
+ }
@@ -0,0 +1,15 @@
1
+ import chalk from 'chalk';
2
+ import { clearAuth, isAuthenticated, getAuth } from '../lib/config.js';
3
+
4
+ export async function logoutCommand(): Promise<void> {
5
+ if (!(await isAuthenticated())) {
6
+ console.log(chalk.yellow('You are not logged in.'));
7
+ return;
8
+ }
9
+
10
+ const auth = await getAuth();
11
+ await clearAuth();
12
+
13
+ console.log(chalk.green(`Logged out successfully.`));
14
+ console.log(chalk.gray(`Goodbye, ${auth?.email}!`));
15
+ }
@@ -0,0 +1,90 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import { listProjects, getLogs } from '../lib/api.js';
6
+ import { isAuthenticated } from '../lib/config.js';
7
+
8
+ export async function logsCommand(nameOrId?: string): Promise<void> {
9
+ // Check authentication
10
+ if (!(await isAuthenticated())) {
11
+ console.log(chalk.red('Please log in first.'));
12
+ console.log(chalk.gray('Run "gazill login" to authenticate.'));
13
+ process.exit(1);
14
+ }
15
+
16
+ let projectId: string | undefined;
17
+ let projectName: string | undefined;
18
+
19
+ // If no name provided, try to get from current directory
20
+ if (!nameOrId) {
21
+ const projectConfigPath = path.join(process.cwd(), '.gazill', 'project.json');
22
+ try {
23
+ const configContent = await fs.readFile(projectConfigPath, 'utf-8');
24
+ const projectConfig = JSON.parse(configContent) as {
25
+ id: string;
26
+ name: string;
27
+ };
28
+ projectId = projectConfig.id;
29
+ projectName = projectConfig.name;
30
+ } catch {
31
+ console.log(chalk.red('No project specified.'));
32
+ console.log(
33
+ chalk.gray('Run "gazill logs <project-name>" or run from a project directory.')
34
+ );
35
+ process.exit(1);
36
+ }
37
+ } else {
38
+ // Find project by name or ID
39
+ const spinner = ora('Finding project...').start();
40
+ try {
41
+ const { projects } = await listProjects();
42
+ const project = projects.find(
43
+ (p) => p.name === nameOrId || p.id === nameOrId
44
+ );
45
+
46
+ if (!project) {
47
+ spinner.fail(chalk.red(`Project "${nameOrId}" not found.`));
48
+ process.exit(1);
49
+ }
50
+
51
+ projectId = project.id;
52
+ projectName = project.name;
53
+ spinner.stop();
54
+ } catch (error) {
55
+ const message = error instanceof Error ? error.message : 'Failed to find project';
56
+ spinner.fail(chalk.red(message));
57
+ process.exit(1);
58
+ }
59
+ }
60
+
61
+ // Fetch logs
62
+ const spinner = ora(`Fetching logs for ${projectName}...`).start();
63
+
64
+ try {
65
+ const { logs } = await getLogs(projectId, 100);
66
+
67
+ spinner.stop();
68
+
69
+ if (logs.length === 0) {
70
+ console.log(chalk.yellow('No logs available.'));
71
+ console.log(
72
+ chalk.gray('The container may not have started yet or has no output.')
73
+ );
74
+ return;
75
+ }
76
+
77
+ console.log(chalk.bold(`\nLogs for ${projectName}:\n`));
78
+ console.log(chalk.gray('-'.repeat(60)));
79
+
80
+ for (const entry of logs) {
81
+ console.log(entry.message);
82
+ }
83
+
84
+ console.log(chalk.gray('-'.repeat(60)));
85
+ } catch (error) {
86
+ const message = error instanceof Error ? error.message : 'Failed to fetch logs';
87
+ spinner.fail(chalk.red(message));
88
+ process.exit(1);
89
+ }
90
+ }
@@ -0,0 +1,162 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import { projectNameSchema, BASE_DOMAIN } from '@gazill/shared';
6
+ import { createProject } from '../lib/api.js';
7
+ import { isAuthenticated } from '../lib/config.js';
8
+ import { startWatcher } from '../lib/watcher.js';
9
+
10
+ // Starter files for a basic Node.js project
11
+ const STARTER_FILES = {
12
+ 'package.json': JSON.stringify(
13
+ {
14
+ name: '{{PROJECT_NAME}}',
15
+ version: '1.0.0',
16
+ scripts: {
17
+ start: 'node index.js',
18
+ },
19
+ },
20
+ null,
21
+ 2
22
+ ),
23
+ 'index.js': `const http = require('http');
24
+
25
+ const port = process.env.PORT || 3000;
26
+
27
+ const server = http.createServer((req, res) => {
28
+ res.writeHead(200, { 'Content-Type': 'text/html' });
29
+ res.end('<h1>Hello from Gazill!</h1><p>Edit index.js and save to see changes.</p>');
30
+ });
31
+
32
+ server.listen(port, () => {
33
+ console.log(\`Server running on port \${port}\`);
34
+ });
35
+ `,
36
+ };
37
+
38
+ export async function newCommand(name: string): Promise<void> {
39
+ // Check authentication
40
+ if (!(await isAuthenticated())) {
41
+ console.log(chalk.red('Please log in first.'));
42
+ console.log(chalk.gray('Run "gazill login" to authenticate.'));
43
+ process.exit(1);
44
+ }
45
+
46
+ // Validate project name
47
+ try {
48
+ projectNameSchema.parse(name);
49
+ } catch {
50
+ console.log(chalk.red('Invalid project name.'));
51
+ console.log(
52
+ chalk.gray(
53
+ 'Project names must be 3-63 characters, lowercase alphanumeric with hyphens.'
54
+ )
55
+ );
56
+ console.log(chalk.gray('Example: my-awesome-app'));
57
+ process.exit(1);
58
+ }
59
+
60
+ // Check if directory already exists
61
+ const projectDir = path.resolve(process.cwd(), name);
62
+ try {
63
+ await fs.access(projectDir);
64
+ console.log(chalk.red(`Directory "${name}" already exists.`));
65
+ process.exit(1);
66
+ } catch {
67
+ // Directory doesn't exist, good to proceed
68
+ }
69
+
70
+ // Create project via API
71
+ const spinner = ora('Creating project...').start();
72
+
73
+ try {
74
+ const { project, url } = await createProject(name);
75
+
76
+ // Create local directory
77
+ await fs.mkdir(projectDir, { recursive: true });
78
+
79
+ // Create starter files
80
+ for (const [filename, content] of Object.entries(STARTER_FILES)) {
81
+ const fileContent = content.replace('{{PROJECT_NAME}}', name);
82
+ await fs.writeFile(path.join(projectDir, filename), fileContent, 'utf-8');
83
+ }
84
+
85
+ // Create .gazill directory with project config
86
+ const gazillDir = path.join(projectDir, '.gazill');
87
+ await fs.mkdir(gazillDir, { recursive: true });
88
+ await fs.writeFile(
89
+ path.join(gazillDir, 'project.json'),
90
+ JSON.stringify(
91
+ {
92
+ id: project.id,
93
+ name: project.name,
94
+ subdomain: project.subdomain,
95
+ },
96
+ null,
97
+ 2
98
+ ),
99
+ 'utf-8'
100
+ );
101
+
102
+ spinner.succeed(chalk.green('Project created!'));
103
+
104
+ console.log('');
105
+ console.log(chalk.blue('Project:'), name);
106
+ console.log(chalk.blue('URL:'), chalk.underline(url));
107
+ console.log('');
108
+ console.log(chalk.gray('Starting file watcher...'));
109
+ console.log('');
110
+
111
+ // Change to project directory and start watcher
112
+ process.chdir(projectDir);
113
+
114
+ await startWatcher({
115
+ projectId: project.id,
116
+ projectDir,
117
+ });
118
+ } catch (error) {
119
+ const message = error instanceof Error ? error.message : 'Failed to create project';
120
+ spinner.fail(chalk.red(message));
121
+ process.exit(1);
122
+ }
123
+ }
124
+
125
+ // Watch an existing project
126
+ export async function watchCommand(): Promise<void> {
127
+ // Check authentication
128
+ if (!(await isAuthenticated())) {
129
+ console.log(chalk.red('Please log in first.'));
130
+ console.log(chalk.gray('Run "gazill login" to authenticate.'));
131
+ process.exit(1);
132
+ }
133
+
134
+ const projectDir = process.cwd();
135
+ const projectConfigPath = path.join(projectDir, '.gazill', 'project.json');
136
+
137
+ // Check if this is a Gazill project
138
+ try {
139
+ const configContent = await fs.readFile(projectConfigPath, 'utf-8');
140
+ const projectConfig = JSON.parse(configContent) as {
141
+ id: string;
142
+ name: string;
143
+ subdomain: string;
144
+ };
145
+
146
+ console.log(chalk.blue('Project:'), projectConfig.name);
147
+ console.log(
148
+ chalk.blue('URL:'),
149
+ chalk.underline(`https://${projectConfig.subdomain}.${BASE_DOMAIN}`)
150
+ );
151
+ console.log('');
152
+
153
+ await startWatcher({
154
+ projectId: projectConfig.id,
155
+ projectDir,
156
+ });
157
+ } catch {
158
+ console.log(chalk.red('Not a Gazill project.'));
159
+ console.log(chalk.gray('Run "gazill new <name>" to create a new project.'));
160
+ process.exit(1);
161
+ }
162
+ }