@archlast/cli 0.0.1

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 (92) hide show
  1. package/README.md +141 -0
  2. package/dist/analyzer.d.ts +96 -0
  3. package/dist/analyzer.d.ts.map +1 -0
  4. package/dist/analyzer.js +404 -0
  5. package/dist/auth.d.ts +14 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +106 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +322875 -0
  11. package/dist/commands/build.d.ts +6 -0
  12. package/dist/commands/build.d.ts.map +1 -0
  13. package/dist/commands/build.js +36 -0
  14. package/dist/commands/config.d.ts +8 -0
  15. package/dist/commands/config.d.ts.map +1 -0
  16. package/dist/commands/config.js +23 -0
  17. package/dist/commands/data.d.ts +6 -0
  18. package/dist/commands/data.d.ts.map +1 -0
  19. package/dist/commands/data.js +300 -0
  20. package/dist/commands/deploy.d.ts +9 -0
  21. package/dist/commands/deploy.d.ts.map +1 -0
  22. package/dist/commands/deploy.js +59 -0
  23. package/dist/commands/dev.d.ts +10 -0
  24. package/dist/commands/dev.d.ts.map +1 -0
  25. package/dist/commands/dev.js +132 -0
  26. package/dist/commands/generate.d.ts +6 -0
  27. package/dist/commands/generate.d.ts.map +1 -0
  28. package/dist/commands/generate.js +100 -0
  29. package/dist/commands/init.d.ts +7 -0
  30. package/dist/commands/init.d.ts.map +1 -0
  31. package/dist/commands/logs.d.ts +10 -0
  32. package/dist/commands/logs.d.ts.map +1 -0
  33. package/dist/commands/logs.js +38 -0
  34. package/dist/commands/pull.d.ts +16 -0
  35. package/dist/commands/pull.d.ts.map +1 -0
  36. package/dist/commands/pull.js +415 -0
  37. package/dist/commands/restart.d.ts +11 -0
  38. package/dist/commands/restart.d.ts.map +1 -0
  39. package/dist/commands/restart.js +63 -0
  40. package/dist/commands/start.d.ts +11 -0
  41. package/dist/commands/start.d.ts.map +1 -0
  42. package/dist/commands/start.js +74 -0
  43. package/dist/commands/status.d.ts +8 -0
  44. package/dist/commands/status.d.ts.map +1 -0
  45. package/dist/commands/status.js +69 -0
  46. package/dist/commands/stop.d.ts +8 -0
  47. package/dist/commands/stop.d.ts.map +1 -0
  48. package/dist/commands/stop.js +23 -0
  49. package/dist/commands/upgrade.d.ts +12 -0
  50. package/dist/commands/upgrade.d.ts.map +1 -0
  51. package/dist/commands/upgrade.js +77 -0
  52. package/dist/docker/compose.d.ts +3 -0
  53. package/dist/docker/compose.d.ts.map +1 -0
  54. package/dist/docker/compose.js +47 -0
  55. package/dist/docker/config.d.ts +12 -0
  56. package/dist/docker/config.d.ts.map +1 -0
  57. package/dist/docker/config.js +183 -0
  58. package/dist/docker/manager.d.ts +19 -0
  59. package/dist/docker/manager.d.ts.map +1 -0
  60. package/dist/docker/manager.js +239 -0
  61. package/dist/docker/ports.d.ts +6 -0
  62. package/dist/docker/ports.d.ts.map +1 -0
  63. package/dist/docker/restart-on-deploy.d.ts +6 -0
  64. package/dist/docker/restart-on-deploy.d.ts.map +1 -0
  65. package/dist/docker/types.d.ts +36 -0
  66. package/dist/docker/types.d.ts.map +1 -0
  67. package/dist/docker/types.js +1 -0
  68. package/dist/events-listener.d.ts +19 -0
  69. package/dist/events-listener.d.ts.map +1 -0
  70. package/dist/events-listener.js +105 -0
  71. package/dist/generator.d.ts +44 -0
  72. package/dist/generator.d.ts.map +1 -0
  73. package/dist/generator.js +1816 -0
  74. package/dist/generators/di.d.ts +21 -0
  75. package/dist/generators/di.d.ts.map +1 -0
  76. package/dist/generators/di.js +100 -0
  77. package/dist/index.d.ts +7 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +4 -0
  80. package/dist/project.d.ts +18 -0
  81. package/dist/project.d.ts.map +1 -0
  82. package/dist/protocol.d.ts +58 -0
  83. package/dist/protocol.d.ts.map +1 -0
  84. package/dist/protocol.js +5 -0
  85. package/dist/uploader.d.ts +63 -0
  86. package/dist/uploader.d.ts.map +1 -0
  87. package/dist/uploader.js +255 -0
  88. package/dist/watcher.d.ts +13 -0
  89. package/dist/watcher.d.ts.map +1 -0
  90. package/dist/watcher.js +38 -0
  91. package/package.json +58 -0
  92. package/scripts/postinstall.cjs +65 -0
@@ -0,0 +1,6 @@
1
+ interface BuildOptions {
2
+ path?: string;
3
+ }
4
+ export declare function buildCommand(options: BuildOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAMA,UAAU,YAAY;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CvE"}
@@ -0,0 +1,36 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import { CodeAnalyzer } from "../analyzer";
4
+ import { TypeGenerator } from "../generator";
5
+ export async function buildCommand(options) {
6
+ const archlastPath = options.path || ".";
7
+ console.log(chalk.blue.bold("šŸ”Ø Archlast Build\n"));
8
+ const analyzer = new CodeAnalyzer(archlastPath);
9
+ const generator = new TypeGenerator(archlastPath);
10
+ const spinner = ora("Analyzing code...").start();
11
+ try {
12
+ const analysis = await analyzer.analyze();
13
+ await generator.generate(analysis);
14
+ spinner.succeed(chalk.green(`āœ… Generated types for ${analysis.functions.length} function(s)`));
15
+ // Show function breakdown
16
+ if (analysis.functions.length > 0) {
17
+ const byType = analysis.functions.reduce((acc, fn) => {
18
+ acc[fn.type] = (acc[fn.type] || 0) + 1;
19
+ return acc;
20
+ }, {});
21
+ const breakdown = Object.entries(byType)
22
+ .map(([type, count]) => `${count} ${type}(s)`)
23
+ .join(", ");
24
+ console.log(chalk.gray(` (${breakdown})`));
25
+ }
26
+ console.log(chalk.gray("\nGenerated files:"));
27
+ console.log(chalk.gray(" • _generated/api.ts"));
28
+ console.log(chalk.gray(" • _generated/server.ts"));
29
+ console.log(chalk.gray(" • _generated/index.ts"));
30
+ }
31
+ catch (error) {
32
+ spinner.fail(chalk.red("Build failed"));
33
+ console.error(error);
34
+ process.exit(1);
35
+ }
36
+ }
@@ -0,0 +1,8 @@
1
+ interface ConfigOptions {
2
+ path?: string;
3
+ config?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare function configCommand(options: ConfigOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzE"}
@@ -0,0 +1,23 @@
1
+ import chalk from "chalk";
2
+ import { loadDockerConfig } from "../docker/config";
3
+ export async function configCommand(options) {
4
+ const config = loadDockerConfig({
5
+ path: options.path,
6
+ configFile: options.config,
7
+ });
8
+ if (options.json) {
9
+ console.log(JSON.stringify(config, null, 2));
10
+ return;
11
+ }
12
+ console.log(chalk.blue.bold("Archlast Docker Config\n"));
13
+ console.log(`Project: ${config.projectPath}`);
14
+ console.log(`Config: ${config.configFilePath ?? "none"}`);
15
+ console.log(`Env file: ${config.envFilePath ?? "none"}`);
16
+ console.log(`Image: ${config.image}:${config.tag}`);
17
+ console.log(`Container: ${config.containerName}`);
18
+ console.log(`Port: ${config.port}`);
19
+ console.log(`Volume: ${config.dataVolumeName}`);
20
+ console.log(`Config dir: ${config.configDir}`);
21
+ console.log(`Deploy dir: ${config.deployDir}`);
22
+ console.log(`Compose: ${config.composePath}`);
23
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * Data command group for backup, export, import operations
4
+ */
5
+ export declare const dataCommand: Command;
6
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/commands/data.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4DpC;;GAEG;AACH,eAAO,MAAM,WAAW,SAE4C,CAAC"}
@@ -0,0 +1,300 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import { Command } from "commander";
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ const BETTER_AUTH_API_KEY_PREFIX = "arch_";
7
+ /**
8
+ * Data command group for backup, export, import operations
9
+ */
10
+ export const dataCommand = new Command("data")
11
+ .description("Data management commands (backup, export, import)")
12
+ .option("--server <url>", "Server URL", "http://localhost:4000");
13
+ /**
14
+ * Get API key from environment
15
+ */
16
+ async function getAuthCredentials(server) {
17
+ // Check API key first
18
+ const apiKey = process.env.ARCHLAST_API_KEY;
19
+ if (apiKey) {
20
+ return apiKey;
21
+ }
22
+ // If no token, try to read from .env file
23
+ const envPath = path.join(process.cwd(), ".env");
24
+ if (fs.existsSync(envPath)) {
25
+ const envContent = fs.readFileSync(envPath, "utf-8");
26
+ const keyMatch = envContent.match(/ARCHLAST_API_KEY=(.+)/);
27
+ if (keyMatch && keyMatch[1]) {
28
+ return keyMatch[1].trim();
29
+ }
30
+ }
31
+ throw new Error("API key not found. Set ARCHLAST_API_KEY environment variable, or add it to .env file");
32
+ }
33
+ /**
34
+ * Make authenticated request to server
35
+ */
36
+ async function apiRequest(url, options = {}, token) {
37
+ const headers = {
38
+ ...options.headers,
39
+ "Content-Type": "application/json",
40
+ "x-api-key": token,
41
+ };
42
+ return fetch(url, {
43
+ ...options,
44
+ headers,
45
+ });
46
+ }
47
+ /**
48
+ * Create a snapshot
49
+ */
50
+ dataCommand
51
+ .command("snapshot")
52
+ .description("Create a database snapshot")
53
+ .option("-n, --name <name>", "Snapshot name")
54
+ .option("--include-sqlite", "Include SQLite export (default: false)", false)
55
+ .action(async function (options) {
56
+ const parent = this.parent;
57
+ const serverOpts = parent?.opts() || {};
58
+ const server = serverOpts.server || "http://localhost:4000";
59
+ const spinner = ora("Creating snapshot...").start();
60
+ try {
61
+ const token = await getAuthCredentials(server);
62
+ const response = await apiRequest(`${server}/_archlast/admin/backup/snapshot`, {
63
+ method: "POST",
64
+ body: JSON.stringify({ name: options.name }),
65
+ }, token);
66
+ const result = (await response.json());
67
+ if (!response.ok || !result.success) {
68
+ spinner.fail(chalk.red(`Failed to create snapshot: ${result.error || "Unknown error"}`));
69
+ process.exit(1);
70
+ }
71
+ spinner.succeed(chalk.green(`āœ… Snapshot created: ${result.snapshotFile}`));
72
+ console.log(chalk.gray(` Records: ${result.recordCount}`));
73
+ console.log(chalk.gray(` Collections: ${result.collections.length}`));
74
+ }
75
+ catch (error) {
76
+ spinner.fail(chalk.red("Failed to create snapshot"));
77
+ console.error(error);
78
+ process.exit(1);
79
+ }
80
+ });
81
+ /**
82
+ * Export data to a file
83
+ */
84
+ dataCommand
85
+ .command("export <outputFile>")
86
+ .description("Export all data to a ZIP file")
87
+ .option("-f, --format <format>", "Export format: zip or json", "zip")
88
+ .action(async function (outputFile, options) {
89
+ const parent = this.parent;
90
+ const serverOpts = parent?.opts() || {};
91
+ const server = serverOpts.server || "http://localhost:4000";
92
+ const spinner = ora("Exporting data...").start();
93
+ try {
94
+ const token = await getAuthCredentials(server);
95
+ const response = await apiRequest(`${server}/_archlast/admin/backup/export`, {}, token);
96
+ if (!response.ok) {
97
+ const result = (await response.json());
98
+ spinner.fail(chalk.red(`Failed to export: ${result.error || "Unknown error"}`));
99
+ process.exit(1);
100
+ }
101
+ const outputPath = path.resolve(outputFile);
102
+ if (options.format === "json") {
103
+ const data = (await response.json());
104
+ await fs.promises.writeFile(outputPath, JSON.stringify(data, null, 2), "utf-8");
105
+ const collectionCount = Object.keys(data.collections || {}).length;
106
+ const totalRecords = Object.values(data.collections || {}).reduce((sum, col) => sum + (col?.count || 0), 0);
107
+ spinner.succeed(chalk.green(`āœ… Exported to ${outputFile}`));
108
+ console.log(chalk.gray(` Collections: ${collectionCount}`));
109
+ console.log(chalk.gray(` Records: ${totalRecords}`));
110
+ }
111
+ else {
112
+ const arrayBuffer = await response.arrayBuffer();
113
+ await fs.promises.writeFile(outputPath, Buffer.from(arrayBuffer));
114
+ spinner.succeed(chalk.green(`āœ… Exported to ${outputFile}`));
115
+ }
116
+ }
117
+ catch (error) {
118
+ spinner.fail(chalk.red("Failed to export data"));
119
+ console.error(error);
120
+ process.exit(1);
121
+ }
122
+ });
123
+ /**
124
+ * Restore from a snapshot
125
+ */
126
+ dataCommand
127
+ .command("restore <snapshotFile>")
128
+ .description("Restore database from a snapshot")
129
+ .action(async function (snapshotFile) {
130
+ const parent = this.parent;
131
+ const serverOpts = parent?.opts() || {};
132
+ const server = serverOpts.server || "http://localhost:4000";
133
+ const spinner = ora("Restoring snapshot...").start();
134
+ try {
135
+ const token = await getAuthCredentials(server);
136
+ const response = await apiRequest(`${server}/_archlast/admin/backup/restore`, {
137
+ method: "POST",
138
+ body: JSON.stringify({ snapshotFile }),
139
+ }, token);
140
+ const result = (await response.json());
141
+ if (!response.ok || !result.success) {
142
+ spinner.fail(chalk.red(`Failed to restore: ${result.error || "Unknown error"}`));
143
+ process.exit(1);
144
+ }
145
+ spinner.succeed(chalk.green(`āœ… Restored ${result.recordsImported} records`));
146
+ console.log(chalk.gray(` Collections: ${result.collections.length}`));
147
+ }
148
+ catch (error) {
149
+ spinner.fail(chalk.red("Failed to restore snapshot"));
150
+ console.error(error);
151
+ process.exit(1);
152
+ }
153
+ });
154
+ /**
155
+ * Export data to a file
156
+ */
157
+ dataCommand
158
+ .command("export <outputFile>")
159
+ .description("Export all data to a JSON file")
160
+ .action(async function (outputFile) {
161
+ const parent = this.parent;
162
+ const serverOpts = parent?.opts() || {};
163
+ const server = serverOpts.server || "http://localhost:4000";
164
+ const spinner = ora("Exporting data...").start();
165
+ try {
166
+ const token = await getAuthCredentials(server);
167
+ const response = await apiRequest(`${server}/_archlast/admin/backup/export`, {}, token);
168
+ if (!response.ok) {
169
+ const result = (await response.json());
170
+ spinner.fail(chalk.red(`Failed to export: ${result.error || "Unknown error"}`));
171
+ process.exit(1);
172
+ }
173
+ const data = (await response.json());
174
+ // Write to file
175
+ const outputPath = path.resolve(outputFile);
176
+ await fs.promises.writeFile(outputPath, JSON.stringify(data, null, 2), "utf-8");
177
+ const collectionCount = Object.keys(data.collections || {}).length;
178
+ const totalRecords = Object.values(data.collections || {}).reduce((sum, col) => sum + (col?.count || 0), 0);
179
+ spinner.succeed(chalk.green(`āœ… Exported to ${outputFile}`));
180
+ console.log(chalk.gray(` Collections: ${collectionCount}`));
181
+ console.log(chalk.gray(` Records: ${totalRecords}`));
182
+ }
183
+ catch (error) {
184
+ spinner.fail(chalk.red("Failed to export data"));
185
+ console.error(error);
186
+ process.exit(1);
187
+ }
188
+ });
189
+ /**
190
+ * Import data from a file
191
+ */
192
+ dataCommand
193
+ .command("import <inputFile>")
194
+ .description("Import data from a JSON or ZIP file (auto-detects format)")
195
+ .option("-s, --strategy <strategy>", "Import strategy: replace or merge", "merge")
196
+ .action(async function (inputFile, options) {
197
+ const parent = this.parent;
198
+ const serverOpts = parent?.opts() || {};
199
+ const server = serverOpts.server || "http://localhost:4000";
200
+ const spinner = ora("Importing data...").start();
201
+ try {
202
+ const inputPath = path.resolve(inputFile);
203
+ if (!fs.existsSync(inputPath)) {
204
+ spinner.fail(chalk.red(`File not found: ${inputFile}`));
205
+ process.exit(1);
206
+ }
207
+ const buffer = await fs.promises.readFile(inputPath);
208
+ const isZip = isZipFile(buffer);
209
+ if (isZip) {
210
+ const formData = new FormData();
211
+ formData.append("file", new Blob([buffer]), path.basename(inputFile));
212
+ formData.append("strategy", options.strategy);
213
+ formData.append("verifyChecksums", "true");
214
+ const token = await getAuthCredentials(server);
215
+ const response = await fetch(`${server}/_archlast/admin/backup/restore`, {
216
+ method: "POST",
217
+ headers: {
218
+ "x-api-key": token,
219
+ },
220
+ body: formData,
221
+ });
222
+ const result = (await response.json());
223
+ if (!response.ok || !result.success) {
224
+ spinner.fail(chalk.red(`Failed to import: ${result.error || "Unknown error"}`));
225
+ process.exit(1);
226
+ }
227
+ spinner.succeed(chalk.green(`āœ… Imported ${result.recordsImported} records`));
228
+ console.log(chalk.gray(` Format: ZIP`));
229
+ console.log(chalk.gray(` Collections: ${result.collections.length}`));
230
+ }
231
+ else {
232
+ const content = buffer.toString("utf-8");
233
+ const data = JSON.parse(content);
234
+ const token = await getAuthCredentials(server);
235
+ const response = await apiRequest(`${server}/_archlast/admin/backup/import`, {
236
+ method: "POST",
237
+ body: JSON.stringify({
238
+ data,
239
+ strategy: options.strategy,
240
+ }),
241
+ }, token);
242
+ const result = (await response.json());
243
+ if (!response.ok || !result.success) {
244
+ spinner.fail(chalk.red(`Failed to import: ${result.error || "Unknown error"}`));
245
+ process.exit(1);
246
+ }
247
+ spinner.succeed(chalk.green(`āœ… Imported ${result.recordsImported} records`));
248
+ console.log(chalk.gray(` Format: JSON`));
249
+ console.log(chalk.gray(` Strategy: ${options.strategy}`));
250
+ console.log(chalk.gray(` Collections: ${result.collections.length}`));
251
+ }
252
+ }
253
+ catch (error) {
254
+ spinner.fail(chalk.red("Failed to import data"));
255
+ console.error(error);
256
+ process.exit(1);
257
+ }
258
+ });
259
+ /**
260
+ * Check if a buffer is a ZIP file by checking magic bytes
261
+ */
262
+ function isZipFile(buffer) {
263
+ return (buffer.length >= 4 &&
264
+ buffer[0] === 0x50 &&
265
+ buffer[1] === 0x4b &&
266
+ buffer[2] === 0x03 &&
267
+ buffer[3] === 0x04);
268
+ }
269
+ /**
270
+ * Delete a snapshot
271
+ */
272
+ dataCommand
273
+ .command("delete <snapshotFile>")
274
+ .description("Delete a snapshot file (supports .json and .zip)")
275
+ .action(async function (snapshotFile) {
276
+ const parent = this.parent;
277
+ const serverOpts = parent?.opts() || {};
278
+ const server = serverOpts.server || "http://localhost:4000";
279
+ const spinner = ora("Deleting snapshot...").start();
280
+ try {
281
+ const token = await getAuthCredentials(server);
282
+ const filename = snapshotFile.endsWith(".json") || snapshotFile.endsWith(".zip")
283
+ ? snapshotFile
284
+ : `${snapshotFile}.zip`;
285
+ const response = await apiRequest(`${server}/_archlast/admin/backup/snapshot/${filename}`, {
286
+ method: "DELETE",
287
+ }, token);
288
+ const result = (await response.json());
289
+ if (!response.ok || !result.success) {
290
+ spinner.fail(chalk.red(`Failed to delete: ${result.error || "Unknown error"}`));
291
+ process.exit(1);
292
+ }
293
+ spinner.succeed(chalk.green(`āœ… Deleted snapshot: ${filename}`));
294
+ }
295
+ catch (error) {
296
+ spinner.fail(chalk.red("Failed to delete snapshot"));
297
+ console.error(error);
298
+ process.exit(1);
299
+ }
300
+ });
@@ -0,0 +1,9 @@
1
+ interface DeployOptions {
2
+ path?: string;
3
+ server?: string;
4
+ maxPoll?: number;
5
+ includeNodeModules?: boolean;
6
+ }
7
+ export declare function deployCommand(options: DeployOptions): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAQA,UAAU,aAAa;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFzE"}
@@ -0,0 +1,59 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import { CodeAnalyzer } from "../analyzer";
4
+ import { TypeGenerator } from "../generator";
5
+ import { CodeUploader } from "../uploader";
6
+ export async function deployCommand(options) {
7
+ const archlastPath = options.path || ".";
8
+ const maxPoll = parseInt(String(options.maxPoll || "30"), 10);
9
+ console.log(chalk.blue.bold("šŸš€ Archlast Deploy\n"));
10
+ const analyzer = new CodeAnalyzer(archlastPath);
11
+ const generator = new TypeGenerator(archlastPath);
12
+ const uploader = new CodeUploader(options.server || "http://localhost:4000", archlastPath);
13
+ const spinner = ora("Checking server availability...").start();
14
+ try {
15
+ // Poll server to ensure it's reachable
16
+ const serverReady = await uploader.pollServer(maxPoll, 1000);
17
+ if (!serverReady) {
18
+ spinner.fail(chalk.red(`Server not reachable after ${maxPoll} retries`));
19
+ process.exit(1);
20
+ }
21
+ spinner.text = "Analyzing code...";
22
+ const analysis = await analyzer.analyze();
23
+ spinner.text = "Generating types...";
24
+ await generator.generate(analysis);
25
+ spinner.text = "Checking for changes...";
26
+ const diffCheck = await uploader.checkHashDiff();
27
+ if (!diffCheck.hasChanges) {
28
+ spinner.succeed(chalk.green("āœ… No changes detected, skipping upload"));
29
+ console.log(chalk.gray(`\n🌐 Server: ${options.server || "http://localhost:4000"}`));
30
+ console.log(chalk.green("\n✨ Already up to date!\n"));
31
+ return;
32
+ }
33
+ spinner.text = "Uploading to server...";
34
+ const uploadResult = await uploader.uploadDelta();
35
+ if (!uploadResult.success) {
36
+ spinner.fail(chalk.red(`Upload failed: ${uploadResult.message}`));
37
+ process.exit(1);
38
+ }
39
+ const deploymentType = uploadResult.deploymentType === "delta" ? "Ī” (Delta)" : "Full";
40
+ spinner.succeed(chalk.green(`āœ… Deployed ${analysis.functions.length} function(s) to ${options.server} [${deploymentType}]`));
41
+ console.log(chalk.gray("\nFunctions:"));
42
+ analysis.functions.forEach((f) => {
43
+ console.log(chalk.gray(` - ${f.name} (${f.type})`));
44
+ });
45
+ if (analysis.schema) {
46
+ console.log(chalk.gray("\nāœ“ Schema included"));
47
+ }
48
+ if (diffCheck.reason) {
49
+ console.log(chalk.gray(`\nšŸ“ Change reason: ${diffCheck.reason}`));
50
+ }
51
+ console.log(chalk.green(`\n🌐 Server: ${options.server || "http://localhost:4000"}`));
52
+ console.log(chalk.green("\n✨ Deployment complete!\n"));
53
+ }
54
+ catch (error) {
55
+ spinner.fail(chalk.red("Deployment failed"));
56
+ console.error(error);
57
+ process.exit(1);
58
+ }
59
+ }
@@ -0,0 +1,10 @@
1
+ interface DevOptions {
2
+ port?: string;
3
+ path?: string;
4
+ server?: string;
5
+ maxPoll?: number;
6
+ includeNodeModules?: boolean;
7
+ }
8
+ export declare function devCommand(options: DevOptions): Promise<void>;
9
+ export {};
10
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAWA,UAAU,UAAU;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAmMnE"}
@@ -0,0 +1,132 @@
1
+ import * as path from "path";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import { FileWatcher } from "../watcher";
5
+ import { CodeAnalyzer, CodeDiffer } from "../analyzer";
6
+ import { TypeGenerator } from "../generator";
7
+ import { CodeUploader } from "../uploader";
8
+ import { listenToServerEvents } from "../events-listener";
9
+ export async function devCommand(options) {
10
+ const archlastPath = options.path || ".";
11
+ const maxPoll = parseInt(String(options.maxPoll || "30"), 10);
12
+ console.log(chalk.blue.bold("šŸš€ Archlast Dev Mode\n"));
13
+ const analyzer = new CodeAnalyzer(archlastPath);
14
+ const differ = new CodeDiffer();
15
+ const generator = new TypeGenerator(archlastPath);
16
+ const watcher = new FileWatcher(archlastPath);
17
+ const uploader = new CodeUploader(options.server || "http://localhost:4000", archlastPath);
18
+ let previousAnalysis = null;
19
+ // Initial analysis
20
+ const spinner = ora("Checking server availability...").start();
21
+ try {
22
+ // Poll server to ensure it's reachable
23
+ const serverReady = await uploader.pollServer(maxPoll, 1000);
24
+ if (!serverReady) {
25
+ spinner.fail(chalk.red(`Server not reachable after ${maxPoll} retries`));
26
+ console.log(chalk.yellow("\nšŸ’” Tip: Make sure the Archlast server is running before starting dev mode"));
27
+ process.exit(1);
28
+ }
29
+ spinner.text = "Analyzing code...";
30
+ const analysis = await analyzer.analyze();
31
+ await generator.generate(analysis);
32
+ spinner.text = "Checking for changes...";
33
+ const diffCheck = await uploader.checkHashDiff();
34
+ if (!diffCheck.hasChanges) {
35
+ spinner.succeed(chalk.green(`Found ${analysis.functions.length} function(s) | Generated types | No changes detected`));
36
+ console.log(chalk.gray("\nWatching for changes...\n"));
37
+ }
38
+ else {
39
+ spinner.text = "Uploading to server...";
40
+ const uploadResult = await uploader.uploadDelta();
41
+ if (uploadResult.success) {
42
+ const deploymentType = uploadResult.deploymentType === "delta" ? "Ī”" : "Full";
43
+ spinner.succeed(chalk.green(`Found ${analysis.functions.length} function(s) | Generated types | Uploaded (${deploymentType}) to ${options.server || "http://localhost:4000"}`));
44
+ }
45
+ else {
46
+ spinner.warn(chalk.yellow(`Found ${analysis.functions.length} function(s) | Generated types | Upload failed: ${uploadResult.message}`));
47
+ }
48
+ console.log(chalk.gray("\nWatching for changes...\n"));
49
+ }
50
+ previousAnalysis = analysis;
51
+ }
52
+ catch (error) {
53
+ spinner.fail(chalk.red("Analysis failed"));
54
+ console.error(error);
55
+ process.exit(1);
56
+ }
57
+ // Watch for changes
58
+ watcher.on("change", async (event) => {
59
+ const relativePath = path.relative(process.cwd(), event.path);
60
+ console.log(chalk.yellow(`\nšŸ“ ${event.type}: ${relativePath}`));
61
+ const analyzeSpinner = ora("Re-analyzing...").start();
62
+ try {
63
+ const newAnalysis = await analyzer.analyze();
64
+ if (previousAnalysis) {
65
+ const diff = differ.diff(previousAnalysis, newAnalysis);
66
+ if (diff.added.length > 0) {
67
+ analyzeSpinner.info(chalk.green(`✨ Added ${diff.added.length} function(s)`));
68
+ diff.added.forEach((f) => console.log(chalk.green(` + ${f.name} (${f.type})`)));
69
+ }
70
+ if (diff.modified.length > 0) {
71
+ analyzeSpinner.info(chalk.blue(`šŸ”„ Modified ${diff.modified.length} function(s)`));
72
+ diff.modified.forEach((f) => console.log(chalk.blue(` ~ ${f.name} (${f.type})`)));
73
+ }
74
+ if (diff.removed.length > 0) {
75
+ analyzeSpinner.info(chalk.red(`šŸ—‘ļø Removed ${diff.removed.length} function(s)`));
76
+ diff.removed.forEach((f) => console.log(chalk.red(` - ${f.name} (${f.type})`)));
77
+ }
78
+ if (diff.schemaChanged) {
79
+ analyzeSpinner.info(chalk.magenta("šŸ“Š Schema changed"));
80
+ }
81
+ }
82
+ await generator.generate(newAnalysis);
83
+ analyzeSpinner.text = "Uploading changes...";
84
+ const uploadResult = await uploader.uploadDelta();
85
+ previousAnalysis = newAnalysis;
86
+ if (uploadResult.success) {
87
+ const deploymentType = uploadResult.deploymentType === "delta" ? "Ī”" : "Full";
88
+ analyzeSpinner.succeed(chalk.green(`āœ… Types regenerated | Uploaded (${deploymentType})`));
89
+ }
90
+ else {
91
+ analyzeSpinner.warn(chalk.yellow(`āœ… Types regenerated | Upload failed: ${uploadResult.message}`));
92
+ }
93
+ console.log(chalk.gray("\nWatching for changes...\n"));
94
+ }
95
+ catch (error) {
96
+ analyzeSpinner.fail(chalk.red("Analysis failed"));
97
+ console.error(error);
98
+ }
99
+ });
100
+ watcher.start();
101
+ // Start listening to server events for reactive deployments
102
+ const serverUrl = options.server || "http://localhost:4000";
103
+ console.log(chalk.gray(`\nšŸ”Œ Connected to server events stream (${serverUrl})`));
104
+ const stopListening = listenToServerEvents({
105
+ serverUrl,
106
+ onSchemaUpdated: async () => {
107
+ // Regenerate types when schema is updated on server
108
+ try {
109
+ const analysis = await analyzer.analyze();
110
+ await generator.generate(analysis);
111
+ previousAnalysis = analysis;
112
+ console.log(chalk.green("āœ… Types regenerated from server schema"));
113
+ }
114
+ catch (error) {
115
+ console.error(chalk.red("Failed to regenerate types:"), error);
116
+ }
117
+ },
118
+ onDeploymentComplete: (type) => {
119
+ console.log(chalk.blue(`\n✨ Server deployment complete (${type})`));
120
+ },
121
+ onError: (error) => {
122
+ // Silently ignore connection errors, will retry
123
+ },
124
+ });
125
+ // Handle graceful shutdown
126
+ process.on("SIGINT", () => {
127
+ console.log(chalk.yellow("\n\nšŸ‘‹ Shutting down..."));
128
+ watcher.stop();
129
+ stopListening();
130
+ process.exit(0);
131
+ });
132
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * Generate command with CRUD subcommand
4
+ */
5
+ export declare const generateCommand: Command;
6
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8GpC;;GAEG;AACH,eAAO,MAAM,eAAe,SASU,CAAC"}